Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: problem z podzapytaniem sql
Forum PHP.pl > Forum > Bazy danych > MySQL
mihmih
witam,

pewnie rozwiązanie jest proste, ale tyle już nad tym siedzę że nie potrafię logicznie myśleć...

mamy powiedzmy taką tabelkę:

luty | 15 | k1
luty | 15 | k2
luty | 12 | k1
marzec | 11 | k1
marzec | 15 | k3
kwiecień | 10 | k3
kwiecień | 19 | k1
maj | 17 | k2

i zapytanie

  1. SELECT miesiac, SUM (liczba) FROM tabela WHERE symbol = k1 GROUP BY miesiac


uzyskujemy tabelke

luty | 27
marzec | 11
kwiecień | 19

jak zmienić kod (wprowadzić podzapytanie to chyba najlepsza metoda) aby w posortowanych wynikach miał wszystkie miesiące, czyli żeby doszedł maj z wartością sumy NULL?

trueblue
  1. SELECT t1.miesiac, SUM(IF(t1.symbol='k1',t1.liczba, NULL))
  2. FROM tabela AS t1
  3. LEFT JOIN (SELECT miesiac FROM tabela GROUP BY miesiac) AS t2 ON t1.miesiac=t2.miesiac
  4. GROUP BY t1.miesiac
mihmih
dzięki za odpowiedź, za chwilę się za to wezmę. Ale czy funkcja IF to to same co CASE WHEN... THEN....ELSE... END?
mmmmmmm
@mihmih IF to to samo, co CASE, tylko że IF jest chyba tylko w MySQL, a CASE ma większe możliwości
trueblue
Tak, przy czym CASE warto używać wtedy kiedy porównujemy jedną wartość ze zbiorem wartości.
mihmih
hmm...trochę uprościłem mój problem i nie wiem jak wasze cenne wskazówki przełożyć na moje skomplikowane zapytanie....

Tak naprawdę moje przykładowe zapytanie

  1. SELECT miesiac, SUM (liczba) FROM tabela WHERE symbol = k1 GROUP BY miesiac


wygląda tak, że w klauzuli WHERE znajduje się

  1. ( `zamowienia`.`ID_dzialu_realizujacego` = `dzialy`.`ID_dzialu` AND `zamowienia`.`ID_zamawiajacego` = `zamawiajacy`.`ID_zamawiajacego` AND `widok_pozycje_z_terminami`.`ID_zamowienia` = `zamowienia`.`ID_zamowienia` AND `widok_pozycje_z_terminami`.`ID_wyrobu` = `wyroby4`.`ID_wyrobu` AND `wyroby4`.`ID_waluty` = `waluty`.`ID_waluty` AND `zamowienia`.`reklamacja` = FALSE AND `zamowienia`.`ID_zamawiajacego` NOT IN ( 4, 5, 7, 9 ) AND `zamowienia`.`czy_wewnetrzne` = FALSE AND `zamawiajacy`.`ID_zamawiajacego` = :a AND `dzialy`.`ID_dzialu` = :b ) OR ( `zamowienia`.`ID_dzialu_realizujacego` = `dzialy`.`ID_dzialu` AND `zamowienia`.`ID_zamawiajacego` = `zamawiajacy`.`ID_zamawiajacego` AND `widok_pozycje_z_terminami`.`ID_zamowienia` = `zamowienia`.`ID_zamowienia` AND `widok_pozycje_z_terminami`.`ID_wyrobu` = `wyroby4`.`ID_wyrobu` AND `wyroby4`.`ID_waluty` = `waluty`.`ID_waluty` AND `zamowienia`.`reklamacja` = FALSE AND `zamowienia`.`ID_zamawiajacego` NOT IN ( 4, 5, 7, 9 ) AND `zamowienia`.`czy_wewnetrzne` = FALSE AND `zamawiajacy`.`ID_zamawiajacego` = :a AND :b IS NULL ) OR ( `zamowienia`.`ID_dzialu_realizujacego` = `dzialy`.`ID_dzialu` AND `zamowienia`.`ID_zamawiajacego` = `zamawiajacy`.`ID_zamawiajacego` AND `widok_pozycje_z_terminami`.`ID_zamowienia` = `zamowienia`.`ID_zamowienia` AND `widok_pozycje_z_terminami`.`ID_wyrobu` = `wyroby4`.`ID_wyrobu` AND `wyroby4`.`ID_waluty` = `waluty`.`ID_waluty` AND `zamowienia`.`reklamacja` = FALSE AND `zamowienia`.`ID_zamawiajacego` NOT IN ( 4, 5, 7, 9 ) AND `zamowienia`.`czy_wewnetrzne` = FALSE AND :a IS NULL AND `dzialy`.`ID_dzialu` = :b ) OR ( `zamowienia`.`ID_dzialu_realizujacego` = `dzialy`.`ID_dzialu` AND `zamowienia`.`ID_zamawiajacego` = `zamawiajacy`.`ID_zamawiajacego` AND `widok_pozycje_z_terminami`.`ID_zamowienia` = `zamowienia`.`ID_zamowienia` AND `widok_pozycje_z_terminami`.`ID_wyrobu` = `wyroby4`.`ID_wyrobu` AND `wyroby4`.`ID_waluty` = `waluty`.`ID_waluty` AND `zamowienia`.`reklamacja` = FALSE AND `zamowienia`.`ID_zamawiajacego` NOT IN ( 4, 5, 7, 9 ) AND `zamowienia`.`czy_wewnetrzne` = FALSE AND :a IS NULL AND :b IS NULL )


a więc 4 warunki połączone ORem. I czy ten cały kod powyżej mogę sobie skopiować i wkleić do atrybutu WHEN funkcji CASE?
trueblue
A dlaczego chcesz go wklejać w strukturę CASE? Przecież możesz włączyć w zwykły IF.
Chyba, że masz na myśli jego uproszczenie, ale przyznam, że nie analizowałem.
mihmih
to mogę cały ten kod powyżej użyć jako pierwszy argument funkcji IF? I wtedy już mi to całe wyrażenie nie jest potrzebne w WHERE? Czy musi się tam pojawić drugi raz?
trueblue
Jeśli ten warunek ma zastąpić warunek symbol='k1', to tak.
Zakładam, że będzie działać.
mmmmmmm
1. Zastosuj aliasy. Np. takie:
`zamowienia`=z
`dzialy`=d
`zamawiajacy`=o
`widok_pozycje_z_terminami`=w
`wyroby4`=w4
`waluty`=k
2. Połącz tabele JOINami, nie WHERE. Czyli to:
z.`ID_dzialu_realizujacego` = d.`ID_dzialu`
AND z.`ID_zamawiajacego` = o.`ID_zamawiajacego`
AND w.`ID_zamowienia` = z.`ID_zamowienia`
AND w.`ID_wyrobu` = w4.`ID_wyrobu`
AND w4.`ID_waluty` = k.`ID_waluty`
daj do JOINów
3. we WHERE daj:
z.`reklamacja` = FALSE
AND z.`ID_zamawiajacego` NOT IN ( 4, 5, 7, 9 )
AND z.`czy_wewnetrzne` = FALSE
AND Coalesce(:a, o.`ID_zamawiajacego`) = o.`ID_zamawiajacego`
AND Coalesce(:b, d.`ID_dzialu`) = d.`ID_dzialu`
mihmih
mmmmmm - niestety nie mogę skorzystać z twojej pomocy ponieważ mój śmieszny Base nie obsługuje niektórych funkcji SQL np. COALESCE. Na szczęście IF działa. Dlatego opieram się na razie na pomocy trueblue....i patrzę w ten kod godziami i nic nie pomaga....

przerobiłem moje zapytanie na ten wzór:


  1. pobierz, plaintext
  2. SELECT t1.miesiac, SUM(IF(t1.symbol='k1',t1.liczba, NULL))
  3. FROM tabela AS t1
  4. LEFT JOIN (SELECT miesiac FROM tabela GROUP BY miesiac) AS t2 ON t1.miesiac=t2.miesiac
  5. GROUP BY t1.miesiac
  6. [SQL] pobierz, plaintext
  7.  
  8. i mam coś takiego:
  9.  
  10.  
  11. [sql]SELECT
  12.  
  13. `widok_pozycje_z_terminami`.`okres`,
  14.  
  15.  
  16.  
  17. SUM( IF (
  18.  
  19. ( `zamowienia`.`ID_dzialu_realizujacego` = `dzialy`.`ID_dzialu` AND `zamowienia`.`ID_zamawiajacego` = `zamawiajacy`.`ID_zamawiajacego` AND `widok_pozycje_z_terminami`.`ID_zamowienia` = `zamowienia`.`ID_zamowienia` AND `widok_pozycje_z_terminami`.`ID_wyrobu` = `wyroby4`.`ID_wyrobu` AND `wyroby4`.`ID_waluty` = `waluty`.`ID_waluty` AND `zamowienia`.`reklamacja` = FALSE AND `zamowienia`.`ID_zamawiajacego` NOT IN ( 4, 5, 7, 9 ) AND `zamowienia`.`czy_wewnetrzne` = FALSE AND `zamawiajacy`.`ID_zamawiajacego` = :a AND `dzialy`.`ID_dzialu` = :b ) OR ( `zamowienia`.`ID_dzialu_realizujacego` = `dzialy`.`ID_dzialu` AND `zamowienia`.`ID_zamawiajacego` = `zamawiajacy`.`ID_zamawiajacego` AND `widok_pozycje_z_terminami`.`ID_zamowienia` = `zamowienia`.`ID_zamowienia` AND `widok_pozycje_z_terminami`.`ID_wyrobu` = `wyroby4`.`ID_wyrobu` AND `wyroby4`.`ID_waluty` = `waluty`.`ID_waluty` AND `zamowienia`.`reklamacja` = FALSE AND `zamowienia`.`ID_zamawiajacego` NOT IN ( 4, 5, 7, 9 ) AND `zamowienia`.`czy_wewnetrzne` = FALSE AND `zamawiajacy`.`ID_zamawiajacego` = :a AND :b IS NULL ) OR ( `zamowienia`.`ID_dzialu_realizujacego` = `dzialy`.`ID_dzialu` AND `zamowienia`.`ID_zamawiajacego` = `zamawiajacy`.`ID_zamawiajacego` AND `widok_pozycje_z_terminami`.`ID_zamowienia` = `zamowienia`.`ID_zamowienia` AND `widok_pozycje_z_terminami`.`ID_wyrobu` = `wyroby4`.`ID_wyrobu` AND `wyroby4`.`ID_waluty` = `waluty`.`ID_waluty` AND `zamowienia`.`reklamacja` = FALSE AND `zamowienia`.`ID_zamawiajacego` NOT IN ( 4, 5, 7, 9 ) AND `zamowienia`.`czy_wewnetrzne` = FALSE AND :a IS NULL AND `dzialy`.`ID_dzialu` = :b ) OR ( `zamowienia`.`ID_dzialu_realizujacego` = `dzialy`.`ID_dzialu` AND `zamowienia`.`ID_zamawiajacego` = `zamawiajacy`.`ID_zamawiajacego` AND `widok_pozycje_z_terminami`.`ID_zamowienia` = `zamowienia`.`ID_zamowienia` AND `widok_pozycje_z_terminami`.`ID_wyrobu` = `wyroby4`.`ID_wyrobu` AND `wyroby4`.`ID_waluty` = `waluty`.`ID_waluty` AND `zamowienia`.`reklamacja` = FALSE AND `zamowienia`.`ID_zamawiajacego` NOT IN ( 4, 5, 7, 9 ) AND `zamowienia`.`czy_wewnetrzne` = FALSE AND :a IS NULL AND :b IS NULL ),
  20.  
  21.  
  22.  
  23.  
  24. ( CASE WHEN `waluty`.`skrot` = 'EUR' THEN `wyroby4`.`cena_wyrobu` * `kursy_walut`.`kurs_euro` ELSE `wyroby4`.`cena_wyrobu` END - ( CASE WHEN `waluty`.`skrot` = 'EUR' THEN `wyroby4`.`cena_wyrobu` * `kursy_walut`.`kurs_euro` ELSE `wyroby4`.`cena_wyrobu` END * `widok_pozycje_z_terminami`.`rabat` / 100 ) ) * `widok_pozycje_z_terminami`.`ilosc`
  25.  
  26. , 0)
  27.  
  28. ) AS `sprzedaz`
  29.  
  30.  
  31. FROM { oj `baza`.`widok_pozycje_z_terminami` AS `widok_pozycje_z_terminami` LEFT OUTER JOIN ( SELECT `okres` FROM `widok_pozycje_z_terminami` GROUP BY `okres` ) AS `wszystkieokresy` ON `widok_pozycje_z_terminami`.`okres` = `wszystkieokresy`.`okres` },
  32.  
  33. `baza`.`zamowienia` AS `zamowienia`, `baza`.`dzialy` AS `dzialy`, `baza`.`zamawiajacy` AS `zamawiajacy`, `baza`.`wyroby4` AS `wyroby4`, `baza`.`waluty` AS `waluty`, `baza`.`kursy_walut` AS `kursy_walut`
  34.  
  35.  
  36.  
  37. GROUP BY `widok_pozycje_z_terminami`.`okres`
  38.  
  39. ORDER BY `widok_pozycje_z_terminami`.`termin` ASC



ale tutaj wyskakuje mi błąd składni, tak jakby było coś nie tak z przecinkami lub nawiasami...może ktoś tu widzi jakiś podstawowy błąd, bo już nie wiem o co tu może chodzić.







trueblue
FROM { oj `baza`

P.S. COALESCE jest odpowiednikiem IFNULL w MySQL, więc może znajdziesz odpowiednik IFNULL u siebie.
mihmih
ten fragment jest akurat ok, Base w taki sposób oznacza takie łączenia tabel (oj to outer join). Jeśli cała funkcje IF zastąpię tylko jej drugim argumentem, a pierwszy argument przesunę do klauzuli WHERE to kwerenda działa. Ale nie tak jakbym chciał - gdy w danym miesiącu nie ma zamówienia to tego miesiąca nie ma w tabeli.

a to nie jest tak że w pierwszym argumencie IFa musi być:

costam = costam?
trueblue
Brakuje trzeciego wyrażenia dla IF.
Obecnie masz (tak w skrócie): SUM(IF(WARUNEK,0)), a powinno być: SUM(IF(WARUNEK,0,coś))
mihmih
mam 3 wyrażenia:

pierwsze to określenie warunku:

  1. ( `zamowienia`.`ID_dzialu_realizujacego` = `dzialy`.`ID_dzialu` AND `zamowienia`.`ID_zamawiajacego` = `zamawiajacy`.`ID_zamawiajacego` AND `widok_pozycje_z_terminami`.`ID_zamowienia` = `zamowienia`.`ID_zamowienia` AND `widok_pozycje_z_terminami`.`ID_wyrobu` = `wyroby4`.`ID_wyrobu` AND `wyroby4`.`ID_waluty` = `waluty`.`ID_waluty` AND `zamowienia`.`reklamacja` = FALSE AND `zamowienia`.`ID_zamawiajacego` NOT IN ( 4, 5, 7, 9 ) AND `zamowienia`.`czy_wewnetrzne` = FALSE AND `zamawiajacy`.`ID_zamawiajacego` = :a AND `dzialy`.`ID_dzialu` = :b ) OR ( `zamowienia`.`ID_dzialu_realizujacego` = `dzialy`.`ID_dzialu` AND `zamowienia`.`ID_zamawiajacego` = `zamawiajacy`.`ID_zamawiajacego` AND `widok_pozycje_z_terminami`.`ID_zamowienia` = `zamowienia`.`ID_zamowienia` AND `widok_pozycje_z_terminami`.`ID_wyrobu` = `wyroby4`.`ID_wyrobu` AND `wyroby4`.`ID_waluty` = `waluty`.`ID_waluty` AND `zamowienia`.`reklamacja` = FALSE AND `zamowienia`.`ID_zamawiajacego` NOT IN ( 4, 5, 7, 9 ) AND `zamowienia`.`czy_wewnetrzne` = FALSE AND `zamawiajacy`.`ID_zamawiajacego` = :a AND :b IS NULL ) OR ( `zamowienia`.`ID_dzialu_realizujacego` = `dzialy`.`ID_dzialu` AND `zamowienia`.`ID_zamawiajacego` = `zamawiajacy`.`ID_zamawiajacego` AND `widok_pozycje_z_terminami`.`ID_zamowienia` = `zamowienia`.`ID_zamowienia` AND `widok_pozycje_z_terminami`.`ID_wyrobu` = `wyroby4`.`ID_wyrobu` AND `wyroby4`.`ID_waluty` = `waluty`.`ID_waluty` AND `zamowienia`.`reklamacja` = FALSE AND `zamowienia`.`ID_zamawiajacego` NOT IN ( 4, 5, 7, 9 ) AND `zamowienia`.`czy_wewnetrzne` = FALSE AND :a IS NULL AND `dzialy`.`ID_dzialu` = :b ) OR ( `zamowienia`.`ID_dzialu_realizujacego` = `dzialy`.`ID_dzialu` AND `zamowienia`.`ID_zamawiajacego` = `zamawiajacy`.`ID_zamawiajacego` AND `widok_pozycje_z_terminami`.`ID_zamowienia` = `zamowienia`.`ID_zamowienia` AND `widok_pozycje_z_terminami`.`ID_wyrobu` = `wyroby4`.`ID_wyrobu` AND `wyroby4`.`ID_waluty` = `waluty`.`ID_waluty` AND `zamowienia`.`reklamacja` = FALSE AND `zamowienia`.`ID_zamawiajacego` NOT IN ( 4, 5, 7, 9 ) AND `zamowienia`.`czy_wewnetrzne` = FALSE AND :a IS NULL AND :b IS NULL ),



drugie to określenie co ma robić gdy jest spełniony ten warunek:

  1. ( CASE WHEN `waluty`.`skrot` = 'EUR' THEN `wyroby4`.`cena_wyrobu` * `kursy_walut`.`kurs_euro` ELSE `wyroby4`.`cena_wyrobu` END - ( CASE WHEN `waluty`.`skrot` = 'EUR' THEN `wyroby4`.`cena_wyrobu` * `kursy_walut`.`kurs_euro` ELSE `wyroby4`.`cena_wyrobu` END * `widok_pozycje_z_terminami`.`rabat` / 100 ) ) * `widok_pozycje_z_terminami`.`ilosc`,



a trzecie to wyrażenie gdy warunek nie jest spełniony:

  1. 0



chyba że źle zrozumiałem funkcję IF....dzięki za chęć pomagania:)
trueblue
Faktycznie, racja, jest ok.
A jaki to dokładnie błąd?
mihmih
Stan SQL: HY000
Kod błędu: 1000

syntax error, unexpected $end, expecting BETWEEN or IN or SQL_TOKEN_LIKE

tylko że to jest chyba wewnętrzny komunikat Base, który pewnie nic Ci nie podpowie...spróbuję jeszcze IF zastąpić CASE, zobaczę co to zmieni.
trueblue
A w Google zerkałeś?
https://forum.openoffice.org/en/forum/viewt...=40&t=39618
mihmih
wiem że istnieje możliwość wykonania kwerendy bezpośrednio w MySqlu, ale nie mogę tego zrobić bo mam tutaj podawanie parametrów poprzez interfejs Base (Mysql nie wie co to jest :a i :cool.gif. Już tyle z tym walczę że nie potrafię myśleć już logicznie. Odpuszczę sobie temat i wrócę za 2, 3 dni ze świeżym umysłem.. Dziękuję bardzo za pomoc.

powracam z dręczącą mnie tematem:)

odpuściłem sobie poprzedni problem, stwierdziłem że większość firm i tak w każdym miesiącu ma jakieś zamówienie. Ale teraz mam kolejną zagadkę. Mamy wersje uproszczoną:

  1. SELECT miesiac, SUM (liczba) FROM tabela WHERE symbol = k1 GROUP BY miesiac


i wynik tego zapytania:

luty | 27
marzec | 11
kwiecień | 19

chciałbym aby w wyniku doszła trzecia kolumna - maksymalna wartość sumy spośród grupowanych miesięcy. Czyli oczekuje czegoś takiego:

luty | 27 | 27
marzec | 11 | 27
kwiecień | 19 | 27

problem chyba znowu dotyczy podzapytań, a to mi sprawia jeszcze problemy, szukałem na necie rozwiązań problemów MAX ( SUM() ), ale nie potrafię sobie z tym poradzić sam...

trueblue
SELECT miesiac, SUM(liczba),(SELECT MAX(liczba) FROM tabela WHERE symbol = 'k1' GROUP BY miesiac) AS maksimum FROM tabela WHERE symbol = 'k1' GROUP BY miesiac
mmmmmmm
  1. SELECT miesiac, SUM(liczba),(SELECT MAX(liczba) FROM (SELECT Sum(liczba) liczba FROM tabela WHERE symbol = 'k1' GROUP BY miesiac)x) AS maksimum FROM tabela WHERE symbol = 'k1' GROUP BY miesiac
mihmih
dzięki za odpowiedź

nie możemy zrobić MAX (liczba), ponieważ chodzi mi o MAX ( SUM (liczba) ). I nie wiem czy takie wyrażenie możemy w ogóle mieć w podzapytania i grupować je.

mmmmmmm - ten x pomiędzy nawiasami oznacza ALIAS?

pomysł mmmmmmm działa, wielkie dzięki za pomoc.
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.