Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Zapytanie SQL zwraca dane z wielu tabel

Część 1 — Połączenia i związki

Ta odpowiedź obejmuje:

  1. Część 1
    • Łączenie dwóch lub więcej tabel za pomocą sprzężenia wewnętrznego (zobacz wpis wikipedii aby uzyskać dodatkowe informacje)
    • Jak używać zapytania składającego
    • Lewe i prawe połączenia zewnętrzne (ta odpowiedź stackOverflow doskonale nadaje się do opisywania typów złączeń)
    • Przecinaj zapytania (i jak je odtworzyć, jeśli Twoja baza danych ich nie obsługuje) — jest to funkcja SQL-Server (zobacz informacje ) i część dlaczego napisałem to wszystko po pierwsze.
  2. Część 2
    • Podzapytania – czym są, gdzie można ich użyć i na co uważać
    • Kartezjanin dołącza do AKA – Och, nieszczęście!

Istnieje wiele sposobów pobierania danych z wielu tabel w bazie danych. W tej odpowiedzi będę używał składni łączenia ANSI-92. Może to różnić się od wielu innych samouczków, które używają starszej składni ANSI-89 (a jeśli jesteś przyzwyczajony do 89, może wydawać się o wiele mniej intuicyjny - ale wszystko, co mogę powiedzieć, to spróbować), ponieważ jest dużo łatwiej zrozumieć, gdy zapytania stają się coraz bardziej złożone. Dlaczego go używać? Czy istnieje wzrost wydajności? krótka odpowiedź nie, ale jest łatwiej czytać, gdy się do tego przyzwyczaisz. Łatwiej jest czytać zapytania napisane przez innych przy użyciu tej składni.

Zamierzam również wykorzystać koncepcję małego warsztatu, który posiada bazę danych do śledzenia dostępnych samochodów. Właściciel zatrudnił Cię jako swojego informatyka i oczekuje, że będziesz mógł przekazać mu dane, o które prosi, w mgnieniu oka.

Zrobiłem kilka tabel przeglądowych, które będą używane przez stół finałowy. To da nam rozsądny model do pracy. Na początek będę uruchamiał moje zapytania względem przykładowej bazy danych, która ma następującą strukturę. Postaram się pomyśleć o typowych błędach popełnianych na początku i wyjaśnić, co jest z nimi nie tak - a także oczywiście pokazać, jak je poprawić.

Pierwsza tabela to po prostu lista kolorów, dzięki której wiemy, jakie kolory mamy na placu samochodowym.

mysql> create table colors(id int(3) not null auto_increment primary key, 
    -> color varchar(15), paint varchar(10));
Query OK, 0 rows affected (0.01 sec)

mysql> show columns from colors;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(3)      | NO   | PRI | NULL    | auto_increment |
| color | varchar(15) | YES  |     | NULL    |                |
| paint | varchar(10) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)

mysql> insert into colors (color, paint) values ('Red', 'Metallic'), 
    -> ('Green', 'Gloss'), ('Blue', 'Metallic'), 
    -> ('White' 'Gloss'), ('Black' 'Gloss');
Query OK, 5 rows affected (0.00 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysql> select * from colors;
+----+-------+----------+
| id | color | paint    |
+----+-------+----------+
|  1 | Red   | Metallic |
|  2 | Green | Gloss    |
|  3 | Blue  | Metallic |
|  4 | White | Gloss    |
|  5 | Black | Gloss    |
+----+-------+----------+
5 rows in set (0.00 sec)

Tabela marek identyfikuje różne marki samochodów, które mogą być sprzedawane na rynku.

mysql> create table brands (id int(3) not null auto_increment primary key, 
    -> brand varchar(15));
Query OK, 0 rows affected (0.01 sec)

mysql> show columns from brands;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(3)      | NO   | PRI | NULL    | auto_increment |
| brand | varchar(15) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.01 sec)

mysql> insert into brands (brand) values ('Ford'), ('Toyota'), 
    -> ('Nissan'), ('Smart'), ('BMW');
Query OK, 5 rows affected (0.00 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysql> select * from brands;
+----+--------+
| id | brand  |
+----+--------+
|  1 | Ford   |
|  2 | Toyota |
|  3 | Nissan |
|  4 | Smart  |
|  5 | BMW    |
+----+--------+
5 rows in set (0.00 sec)

Tabela modeli obejmuje różne typy samochodów, w tym celu łatwiej będzie używać różnych typów samochodów niż rzeczywistych modeli samochodów.

mysql> create table models (id int(3) not null auto_increment primary key, 
    -> model varchar(15));
Query OK, 0 rows affected (0.01 sec)

mysql> show columns from models;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(3)      | NO   | PRI | NULL    | auto_increment |
| model | varchar(15) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

mysql> insert into models (model) values ('Sports'), ('Sedan'), ('4WD'), ('Luxury');
Query OK, 4 rows affected (0.00 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> select * from models;
+----+--------+
| id | model  |
+----+--------+
|  1 | Sports |
|  2 | Sedan  |
|  3 | 4WD    |
|  4 | Luxury |
+----+--------+
4 rows in set (0.00 sec)

I wreszcie, aby związać te wszystkie inne stoły, stół, który spaja wszystko razem. Pole ID to w rzeczywistości unikalny numer partii używany do identyfikacji samochodów.

mysql> create table cars (id int(3) not null auto_increment primary key, 
    -> color int(3), brand int(3), model int(3));
Query OK, 0 rows affected (0.01 sec)

mysql> show columns from cars;
+-------+--------+------+-----+---------+----------------+
| Field | Type   | Null | Key | Default | Extra          |
+-------+--------+------+-----+---------+----------------+
| id    | int(3) | NO   | PRI | NULL    | auto_increment |
| color | int(3) | YES  |     | NULL    |                |
| brand | int(3) | YES  |     | NULL    |                |
| model | int(3) | YES  |     | NULL    |                |
+-------+--------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

mysql> insert into cars (color, brand, model) values (1,2,1), (3,1,2), (5,3,1), 
    -> (4,4,2), (2,2,3), (3,5,4), (4,1,3), (2,2,1), (5,2,3), (4,5,1);
Query OK, 10 rows affected (0.00 sec)
Records: 10  Duplicates: 0  Warnings: 0

mysql> select * from cars;
+----+-------+-------+-------+
| id | color | brand | model |
+----+-------+-------+-------+
|  1 |     1 |     2 |     1 |
|  2 |     3 |     1 |     2 |
|  3 |     5 |     3 |     1 |
|  4 |     4 |     4 |     2 |
|  5 |     2 |     2 |     3 |
|  6 |     3 |     5 |     4 |
|  7 |     4 |     1 |     3 |
|  8 |     2 |     2 |     1 |
|  9 |     5 |     2 |     3 |
| 10 |     4 |     5 |     1 |
+----+-------+-------+-------+
10 rows in set (0.00 sec)

To da nam wystarczającą ilość danych (mam nadzieję), że omówimy poniższe przykłady różnych typów złączeń, a także da nam wystarczającą ilość danych, aby były warte zachodu.

Wchodząc więc w sedno, szef chce znać identyfikatory wszystkich posiadanych przez siebie samochodów sportowych .

To jest proste złączenie dwóch tabel. Posiadamy tabelę identyfikującą model oraz tabelę z dostępnym w niej stanem magazynowym. Jak widać, dane w model kolumna cars tabela odnosi się do models kolumna cars stół mamy. Teraz wiemy, że tabela modeli ma identyfikator 1 dla Sports więc napiszmy dołączenie.

select
    ID,
    model
from
    cars
        join models
            on model=ID

Więc to zapytanie wygląda dobrze, prawda? Zidentyfikowaliśmy dwie tabele i zawieramy potrzebne nam informacje oraz używamy złączenia, które poprawnie identyfikuje, które kolumny mają się połączyć.

ERROR 1052 (23000): Column 'ID' in field list is ambiguous

Och nie! Błąd w naszym pierwszym zapytaniu! Tak, i to jest śliwka. Widzisz, zapytanie rzeczywiście zawiera prawidłowe kolumny, ale niektóre z nich istnieją w obu tabelach, więc baza danych nie wie, o jaką konkretną kolumnę mamy na myśli i gdzie. Istnieją dwa rozwiązania tego problemu. Pierwsza jest ładna i prosta, możemy użyć tableName.columnName aby dokładnie powiedzieć bazie danych, co mamy na myśli, w ten sposób:

select
    cars.ID,
    models.model
from
    cars
        join models
            on cars.model=models.ID

+----+--------+
| ID | model  |
+----+--------+
|  1 | Sports |
|  3 | Sports |
|  8 | Sports |
| 10 | Sports |
|  2 | Sedan  |
|  4 | Sedan  |
|  5 | 4WD    |
|  7 | 4WD    |
|  9 | 4WD    |
|  6 | Luxury |
+----+--------+
10 rows in set (0.00 sec)

Drugi jest prawdopodobnie częściej używany i nazywa się aliasingiem tabel. Tabele w tym przykładzie mają ładne i krótkie proste nazwy, ale wpisując coś takiego jak KPI_DAILY_SALES_BY_DEPARTMENT prawdopodobnie szybko by się zestarzał, więc prostym sposobem jest nazwanie tabeli w ten sposób:

select
    a.ID,
    b.model
from
    cars a
        join models b
            on a.model=b.ID

Wróćmy teraz do prośby. Jak widzicie, mamy potrzebne informacje, ale mamy również informacje, o które nie prosiliśmy, więc musimy umieścić klauzulę where w oświadczeniu, aby uzyskać tylko samochody sportowe, o które poproszono. Ponieważ wolę metodę aliasów tabeli niż ciągłe używanie nazw tabel, będę się jej trzymać od tego momentu.

Oczywiście musimy dodać klauzulę WHERE do naszego zapytania. Samochody sportowe możemy zidentyfikować po ID=1 lub model='Sports' . Ponieważ identyfikator jest indeksowany, a klucz podstawowy (a zdarza się, że jest mniej pisany), użyjmy go w naszym zapytaniu.

select
    a.ID,
    b.model
from
    cars a
        join models b
            on a.model=b.ID
where
    b.ID=1

+----+--------+
| ID | model  |
+----+--------+
|  1 | Sports |
|  3 | Sports |
|  8 | Sports |
| 10 | Sports |
+----+--------+
4 rows in set (0.00 sec)

Bingo! Szef jest zadowolony. Oczywiście, będąc szefem i nigdy nie jest zadowolony z tego, o co prosił, przegląda informacje, a potem mówi Chcę też kolorów .

Dobra, mamy już napisaną dużą część naszego zapytania, ale musimy użyć trzeciej tabeli, która jest kolorami. Teraz nasza główna tabela informacyjna cars przechowuje identyfikator koloru samochodu, który łączy się z kolumną identyfikatora kolorów. Tak więc, podobnie jak w oryginale, możemy dołączyć do trzeciego stołu:

select
    a.ID,
    b.model
from
    cars a
        join models b
            on a.model=b.ID
        join colors c
            on a.color=c.ID
where
    b.ID=1

+----+--------+
| ID | model  |
+----+--------+
|  1 | Sports |
|  3 | Sports |
|  8 | Sports |
| 10 | Sports |
+----+--------+
4 rows in set (0.00 sec)

Cholera, chociaż tabela została poprawnie połączona, a powiązane kolumny zostały połączone, zapomnieliśmy pobrać rzeczywiste informacje z nowej tabeli, którą właśnie powiązaliśmy.

select
    a.ID,
    b.model,
    c.color
from
    cars a
        join models b
            on a.model=b.ID
        join colors c
            on a.color=c.ID
where
    b.ID=1

+----+--------+-------+
| ID | model  | color |
+----+--------+-------+
|  1 | Sports | Red   |
|  8 | Sports | Green |
| 10 | Sports | White |
|  3 | Sports | Black |
+----+--------+-------+
4 rows in set (0.00 sec)

Racja, to na chwilę szef z naszych pleców. Teraz wyjaśnię to trochę bardziej szczegółowo. Jak widać, from klauzula w naszym oświadczeniu łączy naszą główną tabelę (często używam tabeli, która zawiera informacje, a nie tabeli odnośników lub tabeli wymiarów. Zapytanie działałoby równie dobrze z wszystkimi tabelami przełączanymi, ale miałoby mniej sensu, gdy wrócimy do tego zapytania przeczytać ją za kilka miesięcy, więc często najlepiej jest spróbować napisać zapytanie, które będzie ładne i łatwe do zrozumienia - ułóż je intuicyjnie, stosuj ładne wcięcia, aby wszystko było jak najbardziej czytelne. dalej nauczaj innych, spróbuj zaszczepić te cechy w ich zapytaniach - zwłaszcza jeśli będziesz je rozwiązywać.

Całkowicie możliwe jest łączenie w ten sposób coraz większej liczby tabel.

select
    a.ID,
    b.model,
    c.color
from
    cars a
        join models b
            on a.model=b.ID
        join colors c
            on a.color=c.ID
        join brands d
            on a.brand=d.ID
where
    b.ID=1

Chociaż zapomniałem dołączyć tabelę, w której moglibyśmy chcieć połączyć więcej niż jedną kolumnę w join oświadczenie, oto przykład. Jeśli models tabela miała modele specyficzne dla marki, a zatem miała również kolumnę o nazwie brand które łączyły się z brands tabela na ID pole, można to zrobić w następujący sposób:

select
    a.ID,
    b.model,
    c.color
from
    cars a
        join models b
            on a.model=b.ID
        join colors c
            on a.color=c.ID
        join brands d
            on a.brand=d.ID
            and b.brand=d.ID
where
    b.ID=1

Jak widać, powyższe zapytanie nie tylko łączy połączone tabele z głównymi cars tabela, ale także określa połączenia między już połączonymi tabelami. Jeśli tego nie zrobiono, wynik nazywa się złączeniem kartezjańskim - co jest dbaniem o złe przemówienie. Złączenie kartezjańskie to takie, w którym zwracane są wiersze, ponieważ informacje nie mówią bazie danych, jak ograniczyć wyniki, więc zapytanie zwraca wszystkie wiersze spełniające kryteria.

Aby dać przykład złączenia kartezjańskiego, uruchommy następujące zapytanie:

select
    a.ID,
    b.model
from
    cars a
        join models b

+----+--------+
| ID | model  |
+----+--------+
|  1 | Sports |
|  1 | Sedan  |
|  1 | 4WD    |
|  1 | Luxury |
|  2 | Sports |
|  2 | Sedan  |
|  2 | 4WD    |
|  2 | Luxury |
|  3 | Sports |
|  3 | Sedan  |
|  3 | 4WD    |
|  3 | Luxury |
|  4 | Sports |
|  4 | Sedan  |
|  4 | 4WD    |
|  4 | Luxury |
|  5 | Sports |
|  5 | Sedan  |
|  5 | 4WD    |
|  5 | Luxury |
|  6 | Sports |
|  6 | Sedan  |
|  6 | 4WD    |
|  6 | Luxury |
|  7 | Sports |
|  7 | Sedan  |
|  7 | 4WD    |
|  7 | Luxury |
|  8 | Sports |
|  8 | Sedan  |
|  8 | 4WD    |
|  8 | Luxury |
|  9 | Sports |
|  9 | Sedan  |
|  9 | 4WD    |
|  9 | Luxury |
| 10 | Sports |
| 10 | Sedan  |
| 10 | 4WD    |
| 10 | Luxury |
+----+--------+
40 rows in set (0.00 sec)

Dobry Boże, to brzydkie. Jednak jeśli chodzi o bazę danych, to dokładnie o co proszono. W zapytaniu poprosiliśmy o ID z cars i model z models . Jednak ponieważ nie określiliśmy jak aby dołączyć do tabel, baza danych pasuje co wiersz z pierwszej tabeli z co wiersz z drugiej tabeli.

Ok, więc szef wrócił i znowu chce więcej informacji. Chcę tę samą listę, ale dołączam do niej także pojazdy 4WD .

To jednak daje nam świetną wymówkę, by przyjrzeć się dwóm różnym sposobom osiągnięcia tego. Moglibyśmy dodać kolejny warunek do klauzuli WHERE w następujący sposób:

select
    a.ID,
    b.model,
    c.color
from
    cars a
        join models b
            on a.model=b.ID
        join colors c
            on a.color=c.ID
        join brands d
            on a.brand=d.ID
where
    b.ID=1
    or b.ID=3

Chociaż powyższe będzie działać doskonale, spójrzmy na to inaczej, jest to świetna wymówka, aby pokazać, jak union zapytanie zadziała.

Wiemy, że następujące zwrócą wszystkie samochody sportowe:

select
    a.ID,
    b.model,
    c.color
from
    cars a
        join models b
            on a.model=b.ID
        join colors c
            on a.color=c.ID
        join brands d
            on a.brand=d.ID
where
    b.ID=1

A następujące zwróci wszystkie 4WD:

select
    a.ID,
    b.model,
    c.color
from
    cars a
        join models b
            on a.model=b.ID
        join colors c
            on a.color=c.ID
        join brands d
            on a.brand=d.ID
where
    b.ID=3

Więc dodając union all między nimi, wyniki drugiego zapytania zostaną dołączone do wyników pierwszego zapytania.

select
    a.ID,
    b.model,
    c.color
from
    cars a
        join models b
            on a.model=b.ID
        join colors c
            on a.color=c.ID
        join brands d
            on a.brand=d.ID
where
    b.ID=1
union all
select
    a.ID,
    b.model,
    c.color
from
    cars a
        join models b
            on a.model=b.ID
        join colors c
            on a.color=c.ID
        join brands d
            on a.brand=d.ID
where
    b.ID=3

+----+--------+-------+
| ID | model  | color |
+----+--------+-------+
|  1 | Sports | Red   |
|  8 | Sports | Green |
| 10 | Sports | White |
|  3 | Sports | Black |
|  5 | 4WD    | Green |
|  7 | 4WD    | White |
|  9 | 4WD    | Black |
+----+--------+-------+
7 rows in set (0.00 sec)

Jak widać, najpierw zwracane są wyniki pierwszego zapytania, a następnie wyniki drugiego zapytania.

W tym przykładzie znacznie łatwiej byłoby po prostu użyć pierwszego zapytania, ale union zapytania mogą być świetne w konkretnych przypadkach. Są świetnym sposobem na zwrócenie konkretnych wyników z tabel z tabel, które nie dają się łatwo ze sobą połączyć – lub jeśli o to chodzi całkowicie niepowiązane tabele. Jest jednak kilka zasad, których należy przestrzegać.

  • Typy kolumn z pierwszego zapytania muszą odpowiadać typom kolumn z każdego innego zapytania poniżej.
  • Nazwy kolumn z pierwszego zapytania zostaną użyte do identyfikacji całego zestawu wyników.
  • Liczba kolumn w każdym zapytaniu musi być taka sama.

Teraz możesz zastanawiać się, co różnica polega na używaniu union i union all . union zapytanie usunie duplikaty, podczas gdy union all nie będzie. Oznacza to, że podczas korzystania z union występuje niewielki spadek wydajności ponad union all ale wyniki mogą być tego warte – nie będę jednak spekulować na temat tego typu rzeczy w tym przypadku.

W tej notatce warto odnotować tutaj kilka dodatkowych uwag.

  • Jeśli chcielibyśmy uporządkować wyniki, możemy użyć order by ale nie możesz już używać aliasu. W powyższym zapytaniu dołączam order by a.ID spowodowałoby błąd - jeśli chodzi o wyniki, kolumna nazywa się ID zamiast a.ID - nawet jeśli ten sam alias został użyty w obu zapytaniach.
  • Możemy mieć tylko jedno order by oświadczenie i musi to być ostatnie oświadczenie.

W następnych przykładach dodaję kilka dodatkowych wierszy do naszych tabel.

Dodałem Holden do tabeli marek. Dodałem również wiersz do cars który ma color wartość 12 - który nie ma odniesienia w tabeli kolorów.

Ok, szef znowu wrócił, wykrzykując prośby - *Chcę policzyć każdą markę, którą posiadamy i liczbę samochodów w niej!` - Typowe, po prostu przechodzimy do interesującej części naszej dyskusji, a szef chce więcej pracy .

Dobrze, więc pierwszą rzeczą, którą musimy zrobić, to uzyskać pełną listę możliwych marek.

select
    a.brand
from
    brands a

+--------+
| brand  |
+--------+
| Ford   |
| Toyota |
| Nissan |
| Smart  |
| BMW    |
| Holden |
+--------+
6 rows in set (0.00 sec)

Teraz, gdy dołączymy to do naszej tabeli samochodów, otrzymamy następujący wynik:

select
    a.brand
from
    brands a
        join cars b
            on a.ID=b.brand
group by
    a.brand

+--------+
| brand  |
+--------+
| BMW    |
| Ford   |
| Nissan |
| Smart  |
| Toyota |
+--------+
5 rows in set (0.00 sec)

Co jest oczywiście problemem - nie widzimy żadnej wzmianki o uroczym Holden marka, którą dodałem.

Dzieje się tak, ponieważ złączenie szuka pasujących wierszy w obu tabele. Ponieważ w samochodach nie ma danych typu Holden nie jest zwracany. Tutaj możemy użyć outer Przystąp. To zwróci wszystkie wyniki z jednej tabeli, niezależnie od tego, czy pasują do drugiej tabeli, czy nie:

select
    a.brand
from
    brands a
        left outer join cars b
            on a.ID=b.brand
group by
    a.brand

+--------+
| brand  |
+--------+
| BMW    |
| Ford   |
| Holden |
| Nissan |
| Smart  |
| Toyota |
+--------+
6 rows in set (0.00 sec)

Teraz, gdy już to mamy, możemy dodać cudowną funkcję agregującą, aby uzyskać liczbę i na chwilę zdjąć szefa z naszych pleców.

select
    a.brand,
    count(b.id) as countOfBrand
from
    brands a
        left outer join cars b
            on a.ID=b.brand
group by
    a.brand

+--------+--------------+
| brand  | countOfBrand |
+--------+--------------+
| BMW    |            2 |
| Ford   |            2 |
| Holden |            0 |
| Nissan |            1 |
| Smart  |            1 |
| Toyota |            5 |
+--------+--------------+
6 rows in set (0.00 sec)

I z tym, odsuń szefa czai się.

Teraz, aby wyjaśnić to bardziej szczegółowo, zewnętrzne łączenia mogą być left lub right rodzaj. Lewy lub Prawy określa, która tabela jest w pełni w zestawie. left outer join uwzględni wszystkie wiersze z tabeli po lewej stronie, podczas gdy (zgadłeś) right outer join przenosi wszystkie wyniki z tabeli po prawej do wyników.

Niektóre bazy danych pozwalają na full outer join które przyniosą wyniki (dopasowane lub nie) z obu tabele, ale nie jest to obsługiwane we wszystkich bazach danych.

Teraz prawdopodobnie domyślam się, że w tym momencie zastanawiasz się, czy możesz połączyć typy złączeń w zapytaniu - a odpowiedź brzmi tak, absolutnie możesz.

select
    b.brand,
    c.color,
    count(a.id) as countOfBrand
from
    cars a
        right outer join brands b
            on b.ID=a.brand
        join colors c
            on a.color=c.ID
group by
    a.brand,
    c.color

+--------+-------+--------------+
| brand  | color | countOfBrand |
+--------+-------+--------------+
| Ford   | Blue  |            1 |
| Ford   | White |            1 |
| Toyota | Black |            1 |
| Toyota | Green |            2 |
| Toyota | Red   |            1 |
| Nissan | Black |            1 |
| Smart  | White |            1 |
| BMW    | Blue  |            1 |
| BMW    | White |            1 |
+--------+-------+--------------+
9 rows in set (0.00 sec)

Dlaczego więc nie są to oczekiwane rezultaty? Dzieje się tak dlatego, że chociaż wybraliśmy połączenie zewnętrzne z samochodów do marek, nie zostało ono określone w połączeniu z kolorami - więc to konkretne połączenie przyniesie tylko wyniki zgodne z obiema tabelami.

Oto zapytanie, które zadziała, aby uzyskać oczekiwane wyniki:

select
    a.brand,
    c.color,
    count(b.id) as countOfBrand
from
    brands a
        left outer join cars b
            on a.ID=b.brand
        left outer join colors c
            on b.color=c.ID
group by
    a.brand,
    c.color

+--------+-------+--------------+
| brand  | color | countOfBrand |
+--------+-------+--------------+
| BMW    | Blue  |            1 |
| BMW    | White |            1 |
| Ford   | Blue  |            1 |
| Ford   | White |            1 |
| Holden | NULL  |            0 |
| Nissan | Black |            1 |
| Smart  | White |            1 |
| Toyota | NULL  |            1 |
| Toyota | Black |            1 |
| Toyota | Green |            2 |
| Toyota | Red   |            1 |
+--------+-------+--------------+
11 rows in set (0.00 sec)

Jak widać, w zapytaniu mamy dwa połączenia zewnętrzne, a wyniki przychodzą zgodnie z oczekiwaniami.

A co z tymi innymi rodzajami złączeń, o które pytasz? A co ze skrzyżowaniami?

Cóż, nie wszystkie bazy danych obsługują intersection ale prawie wszystkie bazy danych pozwolą ci utworzyć przecięcie przez połączenie (lub przynajmniej dobrze ustrukturyzowaną instrukcję gdzie).

Skrzyżowanie to rodzaj złączenia nieco podobny do union jak opisano powyżej - ale różnica polega na tym, że tylko zwraca wiersze danych, które są identyczne (mam na myśli identyczne) między różnymi indywidualnymi zapytaniami połączonymi przez Unię. Zwrócone zostaną tylko wiersze identyczne pod każdym względem.

Prosty przykład byłby taki:

select
    *
from
    colors
where
    ID>2
intersect
select
    *
from
    colors
where
    id<4

Podczas gdy normalny union zapytanie zwróci wszystkie wiersze tabeli (pierwsze zapytanie zwróci cokolwiek powyżej ID>2 a drugie wszystko, co ma ID<4 ), co spowoduje powstanie pełnego zestawu, zapytanie przecinające zwróci tylko wiersz pasujący do id=3 ponieważ spełnia oba kryteria.

Teraz, jeśli Twoja baza danych nie obsługuje intersect zapytanie, powyższe można łatwo wykonać za pomocą następującego zapytania:

select
    a.ID,
    a.color,
    a.paint
from
    colors a
        join colors b
            on a.ID=b.ID
where
    a.ID>2
    and b.ID<4

+----+-------+----------+
| ID | color | paint    |
+----+-------+----------+
|  3 | Blue  | Metallic |
+----+-------+----------+
1 row in set (0.00 sec)

Jeśli chcesz wykonać przecięcie dwóch różnych tabel przy użyciu bazy danych, która z natury nie obsługuje zapytania przecięcia, musisz utworzyć połączenie w każdej kolumnie stołów.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Szczegółowe spojrzenie na indeksowanie baz danych

  2. PHP:wiele zapytań SQL w jednej instrukcji mysql_query

  3. Sortowanie w MySQL przy użyciu kolejności według klauzul

  4. Jak znaleźć liczbę dni między dwiema datami w MySQL?

  5. Tworzenie i używanie procedur składowanych MySQL — samouczek