Kawałek Kodu

Łączyliśmy już w lewo, prawo i w obydwie strony. Nie łączyliśmy jeszcze w górę i w dół, czyli pionowo. Dziś właśnie o łączeniu pionowym wyników, czyli o UNION, UNION ALL, INTERSECT oraz EXCEPT (MINUS). Inaczej nazywamy je złączeniami na zbiorach.
A dlaczego w ogóle określenie "pionowe"? Bo operujemy na dwóch lub więcej zbiorach uzyskanych z kolejnych, występujących jeden pod drugim, zapytaniach. Czyli łączymy w dół.

UNION i UNION ALL zapewne już znasz z MySQL i być może nawet je stosowałeś. Operator UNION pozwala na połączenie wyników uzyskanych z X (X>1, bo głupio robić UNION na jednym zapytaniu) zapytań. W przypadku UNION będzie to suma wyników bez powtórzeń, a w przypadku UNION ALL duplikaty mogą spać spokojnie.

Przykładowe tabele:

klient1:

id_klient login
1 marek
2 zdzisiek
3 heniek

klient2:

id_klient login
1 marek
3 heniek
4 janek

i zapytanie:

SELECT * FROM klient1 AS k1
UNION /* lub UNION ALL */
SELECT * FROM klient2 AS k2

Wynik z UNION:

id_klient login
1 marek
2 zdzisiek
3 heniek
4 janek

Wynik z UNION ALL:

id_klient login
1 marek
2 zdzisiek
3 heniek
1 marek
3 heniek
4 janek

O ile UNION i UNION ALL występują w MySQL natywnie, to co z INTERSECT oraz EXCEPT?

Te nie występują. Na razie, cześć, do następnego wpisu!

Nie, no! Zaraz zaraz. Tak jak wiele razy symulowaliśmy chorobę w szkole podstawowej, emulowaliśmy ostatnio złączenie FULL OUTER JOIN, więc i dziś poemulujemy.

Najpierw przydałoby się wyjaśnić na czym polega działanie INTERSECT oraz EXCEPT. INTERSECT, to inaczej intersekcja, czyli przecięcie zbiorów, czyli jeszcze inaczej część wspólna. A część wspólną, to chyba już uzyskiwałeś, co? No, pewnie. To po prostu złączenie INNER JOIN.

Mając więc zapytanie z INTERSECT:

SELECT * FROM klient1 AS k1
INTERSECT
SELECT * FROM klient2 AS k2

możemy je w MySQL zbudować w postaci:

SELECT DISTINCT k1.* FROM klient1 AS k1
INNER JOIN klient2 AS k2 ON k2.id_klient=k1.id_klient

Tu wynik będzie następujący:

id_klient login
1 marek
3 heniek

I ciekawostka. Podczas złączenia UNION czy też natywnego INTERSECT, obydwa zapytania muszą zwracać taką samą liczbę kolumn i być odpowiednio (w kolejności) tego samego typu. W przypadku INNER JOIN obydwa zapytania mogą operować na różnej ilości kolumn, bowiem i tak na liście SELECT decydujemy jakie wybierzemy kolumny i z jakiej tabeli, czy nawet kilku - czego nie zrobimy przy INTERSECT, bo tam wybieramy naraz z jednej tabeli. Kolumny w obydwu tabelach mogą być również odmiennego typu. Oczywiście wynika to z natury takiego zapytania, ale jak widać ma większe możliwości niż INTERSECT.

A co w takim razie co z EXCEPT (MINUS)?

EXCEPT czyli "oprócz", mówi: weź wyniki ze zbioru 1 i odejmij wyniki ze zbioru 2. Czyli pozostaw tylko rekordy ze zbioru 1, których nie ma w zbiorze 2. Ta złączenie możemy zasymulować poprzez lekką modyfikację LEFT JOIN.

Znów zacznijmy od samego źródła:

SELECT * FROM klient1 AS k1
EXCEPT
SELECT * FROM klient2 AS k2

To daje:

id_klient login
2 zdzisiek

Teraz zbudujmy proste zapytanie z LEFT JOIN:

SELECT k1.* FROM klient1 AS k1
LEFT JOIN klient2 AS k2 ON k2.id_klient=k1.id_klient

W ten sposób uzyskamy:

id_klient login id_klient w k2 ma w tym momencie
1 marek 1
2 zdzisiek null
3 heniek 3

Już widać, że w prosty sposób możemy w MySQL uzyskać wynik jak w przypadku prawdziwego EXCEPT, dodając warunek na null w drugiej tabeli. Bo skoro nie mamy null, to znaczy, że wartość z tabeli 2 jest w tabeli 1, a tej nie chcemy (1 oraz 3). Wtedy zapytanie wygląda po prostu tak:

SELECT k1.* FROM klient1 AS k1
LEFT JOIN klient2 AS k2 ON k2.id_klient=k1.id_klient
WHERE k2.id_klient IS NULL

 

Miłej porannej pionizacji. Do następnego wpisu!

 

Przydatne linki:
Gul gul na full - czyli o złączeniu FULL (OUTER) JOIN w MySQL