Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> Grupowanie, sortowanie, ostatnie 3 wyniki MySQL
diodadioda
post 16.06.2014, 09:40:14
Post #1





Grupa: Zarejestrowani
Postów: 28
Pomógł: 0
Dołączył: 16.06.2014

Ostrzeżenie: (0%)
-----


Witam po raz pierwszy
Niestety poległem w prostej sprawie, jak mi się przynajmniej wydawało..:
Mam następującą tabelę zakupu2014:


|id |indeks |nazwa_towaru |jm |il0osc |cena_zakupu |nazwa_kontrahenta |data_realizacji|
|0 |121 |aaa |kg |12 |12.1 |hh |2014-01-24|
|1 |121 |aaa |kg |12 |13.1 |hh |2014-01-23|
|2 |122 |bbb |szt |12 |14.1 |hh |2014-01-24|
|3 |121 |aaa |kg |12 |10.1 |hh |2014-01-01|
|4 |122 |bbb |szt|12 |9.1 |hh |2014-01-10|
|5 |122 |bbb |szt|12 |1.1 |hh |2014-01-12|

potrzebuje osiągnąc taki wynik jak daje:
Select indeks,cena_zakupu,avg(cena_zakupu),min(cena_zakupu)
from zakupy2014
group by indeks

ale zamiast np avg ostatnią cenę zakupu, przedostatnia cenę zakupu i przedprzedostatnia cenę zakupu -w jednym rekordzie jak to jest właśnie w tym zapytaniu
Oczywiście biorę po uwagę wariant ze zbudowaniem osobnej tabeli z takimi wynikami.
Podkreślam, że dla niektórych indeksów może być tylko ostatnia cena_zakupu.
Ma ktoś pomysł jak to rozwiązać?
Pozdrawiam

Go to the top of the page
+Quote Post
MatKus
post 16.06.2014, 13:12:46
Post #2





Grupa: Zarejestrowani
Postów: 63
Pomógł: 3
Dołączył: 27.08.2008

Ostrzeżenie: (0%)
-----


Jedyne rozwiązanie, jakie mi przychodzi do głowy, to leftjoin z samym sobą, ale to na pewno nie będzie bardzo wydajne.

  1. SELECT tabelka.*, tabelka_1.cena AS cena_1, tabelka_2.cena AS cena2, tabelka_3.cena AS cena_3 FROM tabelka
  2. LEFT JOIN tabelka tabelka_1 ON tabelka.id=(tabelka.id+1)
  3. LEFT JOIN tabelka tabelka_2 ON tabelka.id=(tabelka.id+2)
  4. LEFT JOIN tabelka tabelka_3 ON tabelka.id=(tabelka.id+3)
  5. WHERE <warunki>



Powyższego nie sprawdziłem w praktyce, więc może coś działać źle, ale generalnie idea jest poprawna. Tyle, że powyższy przypadek będzie miał problem, jeśli coś usuniesz z tabeli, wówczas trzeba by go jeszcze bardziej skomplikować.



Chyba, że potrzebujesz tą średnią + ostatnie 3 wyniki, to wówczas po prostu zrób 2 zapytania, powinno to działać szybciej, niż na tych joinach.
Go to the top of the page
+Quote Post
diodadioda
post 16.06.2014, 22:14:51
Post #3





Grupa: Zarejestrowani
Postów: 28
Pomógł: 0
Dołączył: 16.06.2014

Ostrzeżenie: (0%)
-----


Dzięki za podpowiedź ale dalej nie wiem jak skonstrowac warunki do tego, żeby było poprawnie. Piszesz, że można to rozwiązać przez 2 zapytania i szybciej to działa..przy ilości rekordów sięgających nawet 200 000 moze być to istotne. Mógłbyś rozwinąc ten temat.
Pozdrawiam
Go to the top of the page
+Quote Post
MatKus
post 17.06.2014, 07:47:22
Post #4





Grupa: Zarejestrowani
Postów: 63
Pomógł: 3
Dołączył: 27.08.2008

Ostrzeżenie: (0%)
-----


No, te 2 zapytania to najprościej, jak się da.
Twoje zapytanie, które już masz, i drugie jeszcze prostsze, czyli
  1. SELECT <co_ci_trzeba> FROM tabela ORDER BY id DESC LIMIT 3


Chyba, że źle zrozumiałem, o co ci chodzi smile.gif
Go to the top of the page
+Quote Post
kartin
post 17.06.2014, 14:36:24
Post #5





Grupa: Zarejestrowani
Postów: 246
Pomógł: 79
Dołączył: 25.05.2010

Ostrzeżenie: (0%)
-----


  1. SELECT <co_ci_trzeba> FROM tabela ORDER BY id DESC LIMIT 3
To zapytanie zwróci informacje o trzech wierszach największym id. Wcale nie muszą to być trzy ostatnie zakupy.

Cytat(diodadioda @ 16.06.2014, 23:14:51 ) *
Dzięki za podpowiedź ale dalej nie wiem jak skonstruować warunki do tego, żeby było poprawnie.
Same zapytanie jest niepoprawne więc warunki w nim nic nie pomogą.

Swoją drogą to tabela też nie jest poprawna - np. możesz dopisać towar raz w litrach, a przy kolejnym zakupie w kg. Chyba, że jest to celowe. Jeśli nie to poczytaj o postaciach normalnych.

Jeśli zależy ci na wydajności to trzy ostatnie ceny możesz przechowywać w osobnej tabeli. Ich aktualizacje najwygodniej obsłużyć bezpośrednio w bazie danych, za pomocą wyzwalaczy.
  1. CREATE INDEX indeks
  2. ON zakupy2014 (indeks);
  3.  
  4. CREATE TABLE `ostatnie_ceny` (
  5. `indeks` int(11) NOT NULL,
  6. `cena_ost` decimal(8,2) NOT NULL,
  7. `cena_przedost` decimal(8,2) DEFAULT NULL,
  8. `cena_przedprzedost` decimal(8,2) DEFAULT NULL,
  9. PRIMARY KEY (`indeks`),
  10. FOREIGN KEY (`indeks`) REFERENCES `zakupy2014` (`indeks`) ON DELETE CASCADE ON UPDATE CASCADE
  11. ) ENGINE=InnoDB;
  12.  
  13. DROP TRIGGER IF EXISTS ostatnie_ceny;
  14. DELIMITER //
  15.  
  16. CREATE TRIGGER ostatnie_ceny AFTER INSERT ON zakupy2014 FOR EACH ROW
  17. BEGIN
  18. DECLARE v_cena_przedost, v_cena_przedprzedost DECIMAL(8,2) DEFAULT NULL;
  19.  
  20. SELECT cena_ost, cena_przedost INTO v_cena_przedost, v_cena_przedprzedost
  21. FROM ostatnie_ceny
  22. WHERE indeks = NEW.indeks;
  23.  
  24. REPLACE ostatnie_ceny (indeks, cena_ost, cena_przedost, cena_przedprzedost)
  25. VALUE (NEW.indeks, NEW.cena_zakupu, v_cena_przedost, v_cena_przedprzedost);
  26. END//
  27. DELIMITER ;
Trzeba wziąć pod uwagę, że dane w tabeli mogą być zaktualizowane lub usunięte więc i dla tych zdarzeń trzeba napisać wyzwalacze. Jeśli masz pewnośc, że nie będzie żadnych aktualizacji lub kasowania wtedy to co jest wystarczy.


--------------------
Jeśli ten post pomógł to kliknij przycisk po lewej stronie.
Nie pomagam przez PW, GG, e-mail, faks, telegram, znaki dymne, ...
Go to the top of the page
+Quote Post
diodadioda
post 17.06.2014, 16:49:29
Post #6





Grupa: Zarejestrowani
Postów: 28
Pomógł: 0
Dołączył: 16.06.2014

Ostrzeżenie: (0%)
-----


Dzięki bo już zastanawiałem sie nad pivot table żeby zrobic. Mam jednak problem:
CREATE TABLE `ostatnie_ceny` (
`indeks` int(11) NOT NULL,
`cena_ost` decimal(8,2) NOT NULL,
`cena_przedost` decimal(8,2) DEFAULT NULL,
`cena_przedprzedost` decimal(8,2) DEFAULT NULL,
PRIMARY KEY (`indeks`),
FOREIGN KEY (`indeks`) REFERENCES `zakupy2014` (`indeks`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB;
MySQL zwrócił komunikat: Dokumentacja

#1005 - Can't create table 'carboceny.ostatnie_ceny' (errno: 150) (Szczegóły…)

Co może być nie tak?

Nie wiem czy to istotne, ale w tabeli kolumne indeks musialem zmienic na varchar bo niestety kolumna ta może posiadać znaki wymieszane z cyframi:/ Co do budowy bazy to budowa jest importowana z pewnego "magicznego" systemu (skazana jest na jego ułomności) i nie będzie ulegała zmianie czy usuwaniu rekordów. Jako ciekawostka dodam, że poszczególne jm moga być litr i l, ale to temat na kiedy indziej.
BTW Teraz zauważyłem, że wątek ująłem nie w tym dziale co powinienem za co przepraszam.
Go to the top of the page
+Quote Post
kartin
post 17.06.2014, 17:05:00
Post #7





Grupa: Zarejestrowani
Postów: 246
Pomógł: 79
Dołączył: 25.05.2010

Ostrzeżenie: (0%)
-----


Kolumna indeks musi być w obu tabelach tego samego typu. Poza tym na tą w tabeli zakupy2014 musi być nałożony indeks.
  1. CREATE INDEX indeks
  2. ON zakupy2014 (indeks);


--------------------
Jeśli ten post pomógł to kliknij przycisk po lewej stronie.
Nie pomagam przez PW, GG, e-mail, faks, telegram, znaki dymne, ...
Go to the top of the page
+Quote Post
diodadioda
post 17.06.2014, 17:24:14
Post #8





Grupa: Zarejestrowani
Postów: 28
Pomógł: 0
Dołączył: 16.06.2014

Ostrzeżenie: (0%)
-----


No tak myslalem, wiec ten wariant tez sprawdzilem jak tylko ten bład mi wyskoczył. Po uruchomieniu kodu, indeksy założyła ta procedura przez ciebie napisana. Zatrzymuje sie na create table..



CREATE TABLE `ostatnie_ceny` (
`indeks` varchar(15) NOT NULL,
`cena_ost` decimal(8,2) NOT NULL,
`cena_przedost` decimal(8,2) DEFAULT NULL,
`cena_przedprzedost` decimal(8,2) DEFAULT NULL,
PRIMARY KEY (`indeks`),
FOREIGN KEY (`indeks`) REFERENCES `zakupy2014` (`indeks`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB;
MySQL zwrócił komunikat: Dokumentacja

#1005 - Can't create table 'carboceny.ostatnie_ceny' (errno: 150) (Szczegóły…)
Go to the top of the page
+Quote Post
kartin
post 17.06.2014, 17:28:36
Post #9





Grupa: Zarejestrowani
Postów: 246
Pomógł: 79
Dołączył: 25.05.2010

Ostrzeżenie: (0%)
-----


Kod błędu ewidentnie mówi, że jest problem z kluczem obcym. Napisz co zwróci zapytanie.
  1. SHOW CREATE TABLE zakupy2014


--------------------
Jeśli ten post pomógł to kliknij przycisk po lewej stronie.
Nie pomagam przez PW, GG, e-mail, faks, telegram, znaki dymne, ...
Go to the top of the page
+Quote Post
diodadioda
post 17.06.2014, 17:37:32
Post #10





Grupa: Zarejestrowani
Postów: 28
Pomógł: 0
Dołączył: 16.06.2014

Ostrzeżenie: (0%)
-----


Takie cuś
Table
Create Table
zakupy2014
CREATE TABLE `zakupy2014` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`indeks` varchar(15) CHARACTER SET utf8 COLLATE utf8_polish_ci NOT NULL,
`nazwa_towaru` text CHARACTER SET utf8 COLLATE utf8_polish_ci NOT NULL,
`jm` tinytext CHARACTER SET utf8 COLLATE utf8_polish_ci NOT NULL,
`ilosc` float NOT NULL,
`cena_zakupu` float NOT NULL,
`nazwa_kontrahenta` tinytext CHARACTER SET utf8 COLLATE utf8_polish_ci NOT NULL,
`data_realizacji` date NOT NULL,
PRIMARY KEY (`id`),
KEY `indeks` (`indeks`)
) ENGINE=InnoDB AUTO_INCREMENT=11539 DEFAULT CHARSET=latin1
Go to the top of the page
+Quote Post
kartin
post 17.06.2014, 17:44:48
Post #11





Grupa: Zarejestrowani
Postów: 246
Pomógł: 79
Dołączył: 25.05.2010

Ostrzeżenie: (0%)
-----


Więc jednak kolumny indeks w obu tabelach nie są tego samego typu. Popraw to i wtedy zadziała.


--------------------
Jeśli ten post pomógł to kliknij przycisk po lewej stronie.
Nie pomagam przez PW, GG, e-mail, faks, telegram, znaki dymne, ...
Go to the top of the page
+Quote Post
diodadioda
post 17.06.2014, 18:01:50
Post #12





Grupa: Zarejestrowani
Postów: 28
Pomógł: 0
Dołączył: 16.06.2014

Ostrzeżenie: (0%)
-----


[quote name='diodadioda' date='17.06.2014, 18:24:14 ' post='1111477']
CREATE TABLE `ostatnie_ceny` (
`indeks` varchar(15) NOT NULL,

no w kodzie co uruchamiam jest varchar(15)

CREATE TABLE `ostatnie_ceny` (
`indeks` varchar(15) NOT NULL,
`cena_ost` decimal(8,2) NOT NULL,
`cena_przedost` decimal(8,2) DEFAULT NULL,
`cena_przedprzedost` decimal(8,2) DEFAULT NULL,
PRIMARY KEY (`indeks`),
FOREIGN KEY (`indeks`) REFERENCES `zakupy2014` (`indeks`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB;

DROP TRIGGER IF EXISTS ostatnie_ceny;
DELIMITER //

CREATE TRIGGER ostatnie_ceny AFTER INSERT ON zakupy2014 FOR EACH ROW
BEGIN
DECLARE v_cena_przedost, v_cena_przedprzedost DECIMAL(8,2) DEFAULT NULL;

SELECT cena_ost, cena_przedost INTO v_cena_przedost, v_cena_przedprzedost
FROM ostatnie_ceny
WHERE indeks = NEW.indeks;

REPLACE ostatnie_ceny (indeks, cena_ost, cena_przedost, cena_przedprzedost)
VALUE (NEW.indeks, NEW.cena_zakupu, v_cena_przedost, v_cena_przedprzedost);
END//
DELIMITER ;

Chyba ze coś przeoczylem..moze musi byc inny typ zmiennej, ale jaki co by też znaki obsłużył?
Go to the top of the page
+Quote Post
kartin
post 17.06.2014, 18:15:30
Post #13





Grupa: Zarejestrowani
Postów: 246
Pomógł: 79
Dołączył: 25.05.2010

Ostrzeżenie: (0%)
-----


Zadanie dla spostrzegawczych. Znajdź różnice pomiędzy pierwszym a drugim wierszem:
  1. `indeks` varchar(15) CHARACTER SET utf8 COLLATE utf8_polish_ci NOT NULL
  2. `indeks` varchar(15) NOT NULL


--------------------
Jeśli ten post pomógł to kliknij przycisk po lewej stronie.
Nie pomagam przez PW, GG, e-mail, faks, telegram, znaki dymne, ...
Go to the top of the page
+Quote Post
diodadioda
post 17.06.2014, 18:20:08
Post #14





Grupa: Zarejestrowani
Postów: 28
Pomógł: 0
Dołączył: 16.06.2014

Ostrzeżenie: (0%)
-----


Przepraszam ...
Teraz powstaly indeksy, wyzwalacze i ..pusta tabela:

CREATE INDEX indeks
ON zakupy2014 (indeks);# MySQL zwrócił pusty wynik (zero wierszy).

CREATE TABLE `ostatnie_ceny` (
`indeks` varchar(15) CHARACTER SET utf8 COLLATE utf8_polish_ci NOT NULL,
`cena_ost` decimal(8,2) NOT NULL,
`cena_przedost` decimal(8,2) DEFAULT NULL,
`cena_przedprzedost` decimal(8,2) DEFAULT NULL,
PRIMARY KEY (`indeks`),
FOREIGN KEY (`indeks`) REFERENCES `zakupy2014` (`indeks`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB;# MySQL zwrócił pusty wynik (zero wierszy).


DROP TRIGGER IF EXISTS ostatnie_ceny;# MySQL zwrócił pusty wynik (zero wierszy).

DELIMITER //

CREATE TRIGGER ostatnie_ceny AFTER INSERT ON zakupy2014 FOR EACH ROW
BEGIN
DECLARE v_cena_przedost, v_cena_przedprzedost DECIMAL(8,2) DEFAULT NULL;

SELECT cena_ost, cena_przedost INTO v_cena_przedost, v_cena_przedprzedost
FROM ostatnie_ceny
WHERE indeks = NEW.indeks;

REPLACE ostatnie_ceny (indeks, cena_ost, cena_przedost, cena_przedprzedos[...]
Go to the top of the page
+Quote Post
kartin
post 17.06.2014, 18:25:48
Post #15





Grupa: Zarejestrowani
Postów: 246
Pomógł: 79
Dołączył: 25.05.2010

Ostrzeżenie: (0%)
-----


Teraz dodaj sobie coś do tabeli zakupy2014.


--------------------
Jeśli ten post pomógł to kliknij przycisk po lewej stronie.
Nie pomagam przez PW, GG, e-mail, faks, telegram, znaki dymne, ...
Go to the top of the page
+Quote Post
diodadioda
post 17.06.2014, 18:52:23
Post #16





Grupa: Zarejestrowani
Postów: 28
Pomógł: 0
Dołączył: 16.06.2014

Ostrzeżenie: (0%)
-----


No super wink.gif Teraz już wiem dlaczego nie mogę usuwać wierszy.. smile.gif
Wielkie Dzieki, Szacun za wiedzę.
Wreszcie sie wyśpie smile.gif
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Wersja Lo-Fi Aktualny czas: 27.04.2024 - 13:19