Kawałek Kodu

Zdarzyło Ci się pewnie nie raz pracować na więcej niż jednej tabeli (tabeli bazodanowej, a nie wyników meczu). A jeśli tak, to pewnie zdarzyło Ci się również łączyć obydwie przy pomocy złączenia LEFT JOIN. Jeśli nie, to pozwól, że wspomnę pokrótce na czym polega takie złączenie.

Załóżmy, że masz tabele klientów oraz tabele ich zamówień. Jeśli złączysz obydwie poprzez warunek w klauzuli WHERE lub poprzez INNER JOIN, otrzymasz wynik przedstawiający klientów i ich zamówienia. Ale tylko tych klientów, którzy złożyli (tym razem nie złączyli!) zamówienia. Tych, którzy zarejestrowali się w serwisie, ale nie mają zamówień, nie będzie widać w wyniku tego zapytania. Aby wyświetlić wszystkich klientów i zamówienia, należy użyć wspomnianiego złączenia LEFT JOIN. Dla takich klientów w miejscu ich zamówień otrzymasz wartości null.

Wyobraź sobie, że budujesz teraz system, który posiada możliwość filtracji wyników, a dokładnie pokazania wszystkich klientów i tylko tych z zamówieniami (pewnie jest tam jakiś ptaszek w formularzu, którym włączasz i wyłączasz tą opcję).

I tu rodzi się odwieczne pytanie. Czy da się? Czy da się zbudować tak zapytanie, żeby przekazując określoną wartość wybrać daną pulę wyników i wykorzystać tylko jedno złączenie?

Zacznijmy od tabel.

Tabela klient:

id_klient login
1 marek
2 zdzisiek
3 heniek

Tabela zamowienie:

id_zamowienie id_klient suma
1 1 10
2 1 15
3 1 9
4 3 100

Trzy zamówienia złożył klient o loginie marek, jedno zamówienie złożył heniek, a zdzisiek nie złożył zamówienia.

Pokażmy ten wynik budując odpowiednie zapytanie:

SELECT k.login, z.id_zamowienie, z.suma
FROM klient AS k
LEFT JOIN zamowienie AS z ON z.id_klient=k.id_klient
login id_zamowienie suma
marek 1 10
marek 2 15
marek 3 9
zdzisiek null null
heniek 4 100

Jak widać dla klientów, którzy nie złożyli zamówień, otrzymujemy wartość null jako id_zamowienie. Jeśli chcemy wybrać klientów z zamówieniami, to możemy stworzyć warunek zakładający, że wartość id_zamowienie ma być różna od null, lub też większa lub równa 1.
Jednak żaden z tych warunków nie pozwoli poprzez prostą parametryzację na zamienne wybieranie wszystkich rekordów lub klientów z zamówieniami.

Czy aby na pewno?

A gdyby zmienić wartość null na 0? Otrzymamy wtedy wartości id_zamowienie od 0 do X. Jeśli chcemy pokazać wszystkich klientów, to wybieramy wartości większe lub równe 0, a jeśli tylko klientów z zamówieniami, to większe lub równe 1.

Zmieńmy więc zapytanie na (dodaliśmy warunek):

SELECT k.login, z.id_zamowienie, z.suma
FROM klient AS k
LEFT JOIN zamowienie AS z ON z.id_klient=k.id_klient
WHERE COALESCE(z.id_zamowienie,0)>=:zamowili 

Podstawiając do parametru :zamowili wartość 0 (ptaszek w formularzu odznaczony) wybierzemy wszystkich klientów, a podstawiając wartość 1 (ptaszek zaznaczony), klientów z zamówieniami.

 

Ponieważ w czasie gdy piszę te słowa jest schyłek lata i czuć powiew jesieni, to nie pozostaje mi nic innego, jak życzyć Ci ciepłych, choć spóźnionych wakacji. Oczywiście all inclusive!

 

Przydatne linki:
To be or not to be, that is the query...czyli jak unikać dynamicznego budowania zapytania SQL w zależności od istnienia wartości.