Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: funkcja agregująca i grupowanie
Forum PHP.pl > Forum > Bazy danych > MySQL
bpskiba
Witam
Mam taki problemik:
Jest sobie tabela, w której trzymane są kartoteki magazynowe

stan:
id_towaru int(11) NOT NULL
id_magazynu int(11) NOT NULL
id_stanu int(11) NOT NULL PRIMARY KEY
data datetime NOT NULL
ilosc double(15,4) NOT NULL
jedn int(20) NOT NULL
dest mediumint(9) NULL

Budowanie poszczególnych kartotek jest proste:
  1. SELECT DATA, ilosc FROM stan WHERE id_towaru=880 AND dest=6 AND jedn=1 AND id_magazynu=2
  2. ORDER BY DATA DESC, id_stanu DESC


określenie stanu na dany dzień dla kartoteki też jest proste:
  1. SELECT ilosc FROM stan WHERE id_towaru=880 AND dest=6 AND jedn=1 AND id_magazynu=2 AND DATA<'2012-03-03 00:00:00'
  2. ORDER BY DATA DESC, id_stanu DESC
  3. LIMIT 1


Problem zaczyna się gdy chcę wyświetlić stan całego magazynu na żądany dzień.
Proste pytanie wyświetla bzdury:
  1. SELECT MAX(DATA),ilosc,id_magazynu,jedn,dest,id_towaru FROM stan
  2. WHERE id_magazynu=1
  3. GROUP BY id_towaru,id_magazynu,jedn,dest


Częściowo rozwiązałem to następująco:
  1. SELECT s1.id_towaru,s1.dest,s1.ilosc,s1.jedn
  2. FROM stan s1,(SELECT MAX(DATA) dd,id_stanu,id_towaru,dest,jedn,ilosc
  3. FROM stan
  4. WHERE DATA<'2012-03-01 00:00:00' AND id_magazynu=1
  5. GROUP BY id_towaru,dest,id_magazynu,jedn) s2
  6. WHERE s1.DATA=s2.dd AND s1.id_towaru=s2.id_towaru AND s2.dest=s1.dest AND s1.jedn=s2.jedn


Jest to wyjątkowo kiepskie rozwiązanie...
Po pierwsze jego czas jego wykonania jest nie do przyjęcia, a po drugie nie uwzględnia drugiego elementu sortowania (w przypadku tej samej wartości datetime sortuję malejąco po id_stanu).


Będę wdzięczny za wszystkie pomysły i sugestie.

Piotrek
skowron-line
A dlaczego nie grupujesz po dacie questionmark.gif
  1. SELECT DATA, ilosc,id_magazynu,jedn,dest,id_towaru FROM stan
  2. WHERE id_magazynu=1
  3. GROUP BY DATA
bpskiba
Cytat(skowron-line @ 18.03.2012, 18:13:12 ) *
A dlaczego nie grupujesz po dacie questionmark.gif
  1. SELECT DATA, ilosc,id_magazynu,jedn,dest,id_towaru FROM stan
  2. WHERE id_magazynu=1
  3. GROUP BY DATA


Witaj samo grupowanie nie wystarczy gdyż chcę wyszukać dla każdej kartoteki tylko jedną datę - najpóźniejszą, więc musi być SELECT max(data)...... a wtedy grupowanie po dacie traci sens.

Dobrze myślę?

Piotrek
pmir13
W zapytaniu, które wyświetla bzdury nie możesz polegać na wartości pola ilość, bo nie jest ani w group by ani nie używasz na nim funkcji agregującej. Trudno też oczekiwać stanu całego magazynu na dany dzień skoro tego dnia w zapytaniu nigdzie nie określasz.
Co oznaczają pola jedn i dest?
Ile jest różnych towarów i magazynów?
Skoro potrzebujesz sortować nie tylko po dacie, ale też po id, to czy na pewno data jest typu datetime, jeśli tak to jak często się zdarzają modyfikacje stanu tego samego towaru w tym samym magazynie w ciągu jednej sekundy? Bo taka jest właśnie dokładność datetime.
bpskiba
Cytat(pmir13 @ 18.03.2012, 19:05:19 ) *
W zapytaniu, które wyświetla bzdury nie możesz polegać na wartości pola ilość, bo nie jest ani w group by ani nie używasz na nim funkcji agregującej. Trudno też oczekiwać stanu całego magazynu na dany dzień skoro tego dnia w zapytaniu nigdzie nie określasz.
Co oznaczają pola jedn i dest?
Ile jest różnych towarów i magazynów?
Skoro potrzebujesz sortować nie tylko po dacie, ale też po id, to czy na pewno data jest typu datetime, jeśli tak to jak często się zdarzają modyfikacje stanu tego samego towaru w tym samym magazynie w ciągu jednej sekundy? Bo taka jest właśnie dokładność datetime.


jedn - jednostka (kg,litr,itd. )
dest - przeznaczenie (produkcja własna, sprzedaż i kilka innych)
każda kartoteka ma 4 cechy (id_towaru, id magazynu, jednostka, przeznaczenie)
Towarów jest kilka tysięcy (i rośnie)
Magazynów jest kilkanaście

Magazynierzy wprowadzają towar na stan z datą bierzącą. Możliwa jest więc sytuacja gdy dwóch magazynierów w tej samej sekundzie przyjmie ten sam towar. Prawo Merfy'ego mówi, że jak coś się może sp....ić to kiedyś się sp...oli. Zresztą baza danych już pokazała taki przypadek smile.gif Sortowanie po dacie oraz id_stanu przydało się businesssmiley.png
Kartoteka układa się ok i to zostawmy.
Odnośnie zamego zapytania....
Uwagi niewątpliwie słuszne. Pytanie brzmi jak je rozwiązać
. Samego dnia w sposób ostry nie można określić, gdyż towar mógł wpaść na kartotekę dużo wcześniej i nie na każdej kartotece operacje przeprowadza się codziennie.

Piotrek
pmir13
Jeśli chodzi o rozwiązanie to proponuję:

  1. ALTER TABLE stan ADD INDEX towary_data( id_towaru, id_magazynu, jedn, dest, DATA );


oraz

  1. SELECT di.id_stanu, di.DATA, di.id_towaru, di.ilosc, di.jedn, di.dest
  2. FROM
  3. ( SELECT id_towaru, jedn, dest, MAX(DATA) AS DATA
  4. FROM stan
  5. WHERE DATA < '2012-03-03'
  6. AND id_magazynu = 1
  7. GROUP BY id_towaru, jedn, dest
  8. ) dd
  9. JOIN stan di
  10. ON di.id_stanu = ( SELECT MAX(id_stanu)
  11. FROM stan ds
  12. WHERE ds.id_towaru = dd.id_towaru
  13. AND ds.id_magazynu = 1
  14. AND ds.jedn = dd.jedn
  15. AND ds.dest = dd.dest
  16. AND ds.DATA = dd.DATA )
  17.  


Ten indeks wygląda groźnie, ale jest konsekwencją takiej a nie innej struktury danych. Nie wiem jaki czas wykonania zapytania byłby akceptowalny, ale nie sądze by przy tym rozmiarze bazy przekraczał 1s, poza tym pole do optymalizacji jest niewielkie, raczej ciężko będzie znaleźć coś, co da poprawne wyniki w zauważalnie krótszym czasie.
bpskiba


oooooooooo o
To zapytanie wygląda bardzo zachęcająco nerdsmiley.png
Moje zapytanie trwało 4-5 s i to było nie do przyjęcia. Potrzebuję nieco czasu na testy i przemyślenia, ale pierwsze efekty wyglądają doskonale.
Wielkie dzięki za pomoc

Piotrek
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.