Łą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