SQL spojení je místo, kde spustíte dotaz, který spojuje více tabulek.
Tento výukový program spojení SQL představuje základní příklady spojení SQL a také úvod do různých typů spojení.
Typy spojení SQL
Standard ANSI SQL specifikuje pět typů spojení, jak je uvedeno v následující tabulce.
Typ připojení | Popis |
---|---|
INNER JOIN | Vrátí řádky, pokud je v obou tabulkách alespoň jeden řádek, který odpovídá podmínce spojení. |
LEFT OUTER JOIN nebo LEFT JOIN | Vrátí řádky, které obsahují data v levé tabulce (vlevo od JOIN klíčové slovo), i když v pravé tabulce nejsou žádné odpovídající řádky. |
RIGHT OUTER JOIN nebo RIGHT JOIN | Vrátí řádky, které obsahují data v pravé tabulce (vpravo od JOIN klíčové slovo), i když v levé tabulce nejsou žádné odpovídající řádky. |
FULL OUTER JOIN nebo FULL JOIN | Vrátí všechny řádky, pokud jsou v jedné z tabulek odpovídající údaje. |
CROSS JOIN | Vrátí řádky, které kombinují každý řádek z první tabulky s každým řádkem z druhé tabulky. |
Existují také další termíny pro různé operace spojení, například následující:
Připojit se | Popis |
---|---|
Vlastní připojení | Když se tabulka připojí sama k sobě. |
Přirozené připojení | Implicitní spojení založené na společných sloupcích ve dvou spojovaných tabulkách. |
Equi-join | Spojení obsahující pouze porovnání rovnosti v predikátu spojení. |
Syntaxe spojení SQL
Vnitřní spojení lze zadat buď v FROM
nebo WHERE
doložky. Vnější spojení a křížová spojení lze zadat v FROM
pouze doložka.
Chcete-li vytvořit spojení SQL v FROM
klauzule, udělejte něco takového:
SELECT *
FROM Table1 < JoinType > Table2 [ ON ( JoinCondition ) ]
Kde JoinType
určuje, jaký druh spojení se provádí, a JoinCondition
definuje predikát, který má být vyhodnocen pro každý pár spojených řádků.
Chcete-li zadat spojení v WHERE
klauzule, udělejte něco takového:
SELECT *
FROM Table1, Table2 [ WHERE ( JoinCondition ) ]
Opět JoinCondition
definuje predikát, který má být vyhodnocen pro každý pár spojených řádků.
Také vše uzavřeno v hranatých závorkách ([]
) je volitelný.
Ukázkové tabulky pro příklady v tomto kurzu
Většina příkladů v tomto tutoriálu provádí spojení s následujícími dvěma tabulkami.
PetTypes
tabulka:
+-------------+-----------+ | PetTypeId | PetType | |-------------+-----------| | 1 | Bird | | 2 | Cat | | 3 | Dog | | 4 | Rabbit | +-------------+-----------+ (4 rows affected)
Pets
tabulka:
+---------+-------------+-----------+-----------+------------+ | PetId | PetTypeId | OwnerId | PetName | DOB | |---------+-------------+-----------+-----------+------------| | 1 | 2 | 3 | Fluffy | 2020-11-20 | | 2 | 3 | 3 | Fetch | 2019-08-16 | | 3 | 2 | 2 | Scratch | 2018-10-01 | | 4 | 3 | 3 | Wag | 2020-03-15 | | 5 | 1 | 1 | Tweet | 2020-11-28 | | 6 | 3 | 4 | Fluffy | 2020-09-17 | | 7 | 3 | 2 | Bark | NULL | | 8 | 2 | 4 | Meow | NULL | +---------+-------------+-----------+-----------+------------+ (8 rows affected)
Vnitřní spojení
SQL INNER JOIN
vrátí řádky, pokud je v obou tabulkách alespoň jeden řádek, který odpovídá podmínce spojení.
SELECT
Pets.PetName,
PetTypes.PetType
FROM Pets
INNER JOIN PetTypes
ON Pets.PetTypeId = PetTypes.PetTypeId;
Výsledek:
-----------+-----------+ | PetName | PetType | |-----------+-----------| | Fluffy | Cat | | Fetch | Dog | | Scratch | Cat | | Wag | Dog | | Tweet | Bird | | Fluffy | Dog | | Bark | Dog | | Meow | Cat | +-----------+-----------+ (8 rows affected)
Chcete-li určit vnitřní spojení v FROM
klauzule, používáme INNER JOIN
. Používáme také ON
klíčové slovo pro definování predikátu, který má být vyhodnocen pro každý pár spojených řádků.
Bez ohledu na typ spojení kvalifikujeme naše názvy sloupců názvy tabulek. Důvodem, proč to děláme, je vyhnout se jakékoli nejednoznačnosti ohledně názvů sloupců mezi tabulkami. Obě tabulky mohou mít sloupce se stejným názvem (jako v našem příkladu) a v takových případech DBMS nebude vědět, na který sloupec odkazujete. Přidání názvů sloupců před názvy jejich tabulek zajistí, že odkazujete na správný sloupec, a zabráníte jakýmkoli chybám, které by mohly vzniknout v důsledku nejasností ohledně toho, na který sloupec odkazujete.
V tomto příkladu mají obě tabulky PetTypeId
sloupec. Pets.PetTypeId
sloupec je cizí klíč k PetTypes.PetTypeId
sloupec, což je primární klíč pro tuto tabulku.
V tomto příkladu vidíme, že jsou vrácena všechna domácí zvířata, ale ne všechny typy zvířat jsou vráceny. V Pets
nejsou žádní králíci tabulka, a tedy Rabbits
pet type není vrácen.
Důvodem jsou Rabbits
typ není vrácen, protože INNER JOIN
vrátí řádky pouze v případě, že v obou tabulkách existuje alespoň jeden řádek, který odpovídá podmínce spojení. V tomto případě Rabbits
je pouze v jedné tabulce (PetTypes
tabulka).
Všimněte si, že typ spojení je volitelný. Proto většina (pokud ne všechny) DBMS umožňuje vynechat INNER
klíčové slovo. Když toto vynecháte (tj. zadejte pouze JOIN
), předpokládá se, že jde o vnitřní spojení.
Proto bychom mohli výše uvedený příklad přepsat na toto:
SELECT
Pets.PetName,
PetTypes.PetType
FROM Pets
JOIN PetTypes
ON Pets.PetTypeId = PetTypes.PetTypeId;
Stejně jako u jakéhokoli příkazu SQL také FROM
klauzule může být na jednom celém řádku, pokud chcete:
SELECT
Pets.PetName,
PetTypes.PetType
FROM Pets JOIN PetTypes ON Pets.PetTypeId = PetTypes.PetTypeId;
Aliasy
Při provádění spojení SQL je běžnou praxí používat aliasy tabulek. Aliasy pomáhají, aby byl kód stručnější a snáze čitelný.
Proto bychom mohli předchozí příklad změnit na tento:
SELECT
p.PetName,
pt.PetType
FROM Pets p INNER JOIN PetTypes pt
ON p.PetTypeId = pt.PetTypeId;
Výsledek:
-----------+-----------+ | PetName | PetType | |-----------+-----------| | Fluffy | Cat | | Fetch | Dog | | Scratch | Cat | | Wag | Dog | | Tweet | Bird | | Fluffy | Dog | | Bark | Dog | | Meow | Cat | +-----------+-----------+ (8 rows affected)
Equi-Join
Výše uvedené spojení může být také označováno jako equi-join . Rovnocenné spojení je spojení obsahující pouze porovnání rovnosti v predikátu spojení.
Jiný způsob zápisu výše uvedeného spojení je tento:
SELECT
p.PetName,
pt.PetType
FROM
Pets p,
PetTypes pt
WHERE p.PetTypeId = pt.PetTypeId;
Výsledek:
+-----------+-----------+ | PetName | PetType | |-----------+-----------| | Fluffy | Cat | | Fetch | Dog | | Scratch | Cat | | Wag | Dog | | Tweet | Bird | | Fluffy | Dog | | Bark | Dog | | Meow | Cat | +-----------+-----------+
Toto je příklad zadání vnitřního spojení v WHERE
doložka. Jednoduše jsme poskytli čárkami oddělený seznam tabulek a poté WHERE
stav. Pokud bychom vynechali WHERE
stavu, skončili bychom s CROSS JOIN
.
Pro mnoho začátečníků je výše uvedená syntaxe mnohem srozumitelnější než INNER JOIN
syntax. Pokud chcete, klidně použijte tuto syntaxi, mějte však na paměti, že většina SQL profesionálů dává přednost použití INNER JOIN
syntaxe z předchozího příkladu.
Další příklady, včetně vnitřního spojení, které spojuje 3 tabulky, najdete v tématu SQL Inner Join.
Správné spojení
Také známý jako RIGHT OUTER JOIN
, RIGHT JOIN
vrátí řádky, které mají data v pravé tabulce (vpravo od JOIN
klíčové slovo), i když v levé tabulce nejsou žádné odpovídající řádky.
SELECT
p.PetName,
pt.PetType
FROM Pets p
RIGHT JOIN PetTypes pt
ON p.PetTypeId = pt.PetTypeId;
Výsledek:
+-----------+-----------+ | PetName | PetType | |-----------+-----------| | Tweet | Bird | | Fluffy | Cat | | Scratch | Cat | | Meow | Cat | | Fetch | Dog | | Wag | Dog | | Fluffy | Dog | | Bark | Dog | | NULL | Rabbit | +-----------+-----------+ (9 rows affected)
V tomto případě máme navíc PetType
hodnota – Rabbit
– i když v Pets
není žádné zvíře stůl tohoto typu. Výsledkem je NULL
hodnotu v PetName
sloupec proti Rabbit
.
Další příklady, včetně pravého spojení, které spojuje 3 tabulky, najdete v tématu SQL Right Join.
Levé spojení
Také známý jako LEFT OUTER JOIN
, SQL LEFT JOIN
vrátí řádky, které obsahují data v levé tabulce (vlevo od JOIN
klíčové slovo), i když v pravé tabulce nejsou žádné odpovídající řádky.
Toto je opak RIGHT JOIN
.
Pokud změníme předchozí příklad tak, aby používal levé spojení, dostaneme následující výsledek.
SELECT
p.PetName,
pt.PetType
FROM Pets p
LEFT JOIN PetTypes pt
ON p.PetTypeId = pt.PetTypeId;
Výsledek:
+-----------+-----------+ | PetName | PetType | |-----------+-----------| | Fluffy | Cat | | Fetch | Dog | | Scratch | Cat | | Wag | Dog | | Tweet | Bird | | Fluffy | Dog | | Bark | Dog | | Meow | Cat | +-----------+-----------+ (8 rows affected)
V tomto konkrétním případě jsou naše výsledky stejné jako u vnitřního spojení.
Pokud však zaměníme pořadí tabulky v našem FROM
klauzule, dostaneme podobný výsledek jako správné spojení v předchozím příkladu.
SELECT
p.PetName,
pt.PetType
FROM PetTypes pt
LEFT JOIN Pets p
ON p.PetTypeId = pt.PetTypeId;
Výsledek:
+-----------+-----------+ | PetName | PetType | |-----------+-----------| | Tweet | Bird | | Fluffy | Cat | | Scratch | Cat | | Meow | Cat | | Fetch | Dog | | Wag | Dog | | Fluffy | Dog | | Bark | Dog | | NULL | Rabbit | +-----------+-----------+ (9 rows affected)
Můžete tedy vidět, že jakýkoli výsledný rozdíl mezi levým a pravým spojením závisí pouze na tom, jak objednáváte sloupce v FROM
doložka.
Další příklady, včetně levého spojení, které spojuje 3 tabulky, najdete v tématu SQL Left Join.
Úplné připojení
SQL FULL JOIN
(nebo FULL OUTER JOIN
) vrátí všechny řádky, pokud jsou v jedné z tabulek odpovídající údaje.
Jinými slovy, je to jako mít v jednom spojení levé i pravé spojení.
Zde je příklad úplného připojení.
SELECT
p.PetName,
pt.PetType
FROM Pets p
FULL JOIN PetTypes pt
ON p.PetTypeId = pt.PetTypeId;
Výsledek:
+-----------+-----------+ | PetName | PetType | |-----------+-----------| | Fluffy | Cat | | Fetch | Dog | | Scratch | Cat | | Wag | Dog | | Tweet | Bird | | Fluffy | Dog | | Bark | Dog | | Meow | Cat | | NULL | Rabbit | +-----------+-----------+ (9 rows affected)
Vrátí to stejný výsledek, jaký jsme dostali se správným spojením, ale pokud by v levé tabulce byl řádek, který by v pravé tabulce neměl odpovídající hodnotu, vrátilo by to jiný výsledek.
Zaměňme názvy tabulek a spusťte to znovu.
SELECT
p.PetName,
pt.PetType
FROM PetTypes pt
FULL JOIN Pets p
ON p.PetTypeId = pt.PetTypeId;
Výsledek:
+-----------+-----------+ | PetName | PetType | |-----------+-----------| | Tweet | Bird | | Fluffy | Cat | | Scratch | Cat | | Meow | Cat | | Fetch | Dog | | Wag | Dog | | Fluffy | Dog | | Bark | Dog | | NULL | Rabbit | +-----------+-----------+ (9 rows affected)
Stejný výsledek.
Další příklady, včetně úplného spojení, které spojuje 3 tabulky, najdete v tématu SQL Full Join.
The Cross Join
SQL CROSS JOIN
vrátí řádky, které kombinují každý řádek z první tabulky s každým řádkem z druhé tabulky.
Jinými slovy, vrací kartézský součin řádků z tabulek ve spojení.
SELECT
p.PetName,
pt.PetType
FROM Pets p
CROSS JOIN PetTypes pt;
Výsledek:
+-----------+-----------+ | PetName | PetType | |-----------+-----------| | Fluffy | Bird | | Fetch | Bird | | Scratch | Bird | | Wag | Bird | | Tweet | Bird | | Fluffy | Bird | | Bark | Bird | | Meow | Bird | | Fluffy | Cat | | Fetch | Cat | | Scratch | Cat | | Wag | Cat | | Tweet | Cat | | Fluffy | Cat | | Bark | Cat | | Meow | Cat | | Fluffy | Dog | | Fetch | Dog | | Scratch | Dog | | Wag | Dog | | Tweet | Dog | | Fluffy | Dog | | Bark | Dog | | Meow | Dog | | Fluffy | Rabbit | | Fetch | Rabbit | | Scratch | Rabbit | | Wag | Rabbit | | Tweet | Rabbit | | Fluffy | Rabbit | | Bark | Rabbit | | Meow | Rabbit | +-----------+-----------+ (32 rows affected)
Jak si pravděpodobně dokážete představit, mohlo by to být velmi nebezpečné, pokud jej spustíte proti nesprávným tabulkám.
Je to stejné jako toto:
SELECT
p.PetName,
pt.PetType
FROM Pets p, PetTypes pt;
Můžete přidat WHERE
klauzule na křížové spojení, které z něj udělá vnitřní spojení.
Takhle:
SELECT
p.PetName,
pt.PetType
FROM Pets p
CROSS JOIN PetTypes pt
WHERE p.PetTypeId = pt.PetTypeId;
Výsledek:
+-----------+-----------+ | PetName | PetType | |-----------+-----------| | Fluffy | Cat | | Fetch | Dog | | Scratch | Cat | | Wag | Dog | | Tweet | Bird | | Fluffy | Dog | | Bark | Dog | | Meow | Cat | +-----------+-----------+ (8 rows affected)
Další příklady viz SQL Cross Join.
Přirozené spojení
SQL NATURAL JOIN
je typ ekvi-spojení, kde predikát spojení vzniká implicitně porovnáním všech sloupců v obou tabulkách, které mají stejné názvy sloupců ve spojených tabulkách.
Sada výsledků obsahuje pouze jeden sloupec pro každou dvojici stejně pojmenovaných sloupců. Pokud nebudou nalezeny žádné sloupce se stejnými názvy, výsledkem bude křížové spojení.
SELECT
Pets.PetName,
PetTypes.PetType
FROM Pets NATURAL JOIN PetTypes;
Výsledek:
petname | pettype ---------+--------- Fluffy | Cat Fetch | Dog Scratch | Cat Wag | Dog Tweet | Bird Fluffy | Dog Bark | Dog Meow | Cat (8 rows)
Ve skutečnosti přirozené spojení není ve skutečnosti typem spojení, jak je zvažováno standardem ANSI. Je to klíčové slovo, které můžete volitelně vložit, aby se spojení stalo přirozeným spojením.
Proto bychom mohli výše uvedený příklad změnit na NATURAL INNER JOIN
pokud bychom chtěli:
SELECT
Pets.PetName,
PetTypes.PetType
FROM Pets NATURAL INNER JOIN PetTypes;
Jak již bylo zmíněno dříve, vnitřní spojení jsou výchozím typem spojení, takže pokud vynecháte typ spojení (např. INNER
, LEFT
, RIGHT
, atd.), pak se s ním zachází jako s vnitřním spojením.
Pokud formátování těchto výsledků vypadá jinak než předchozí výsledky, je to proto, že jsem musel přeskočit na PostgreSQL, abych mohl spustit tento dotaz. Spustil jsem předchozí příklady v SQL Server, ale SQL Server nepodporuje přirozené spojení.
Další příklady, včetně přirozeného spojení, které spojuje 3 tabulky, najdete v tématu SQL Natural Join.
Sebe připojení
SQL SELF JOIN
připojuje stůl k sobě.
Klasickým příkladem vlastního připojení je tabulka Zaměstnanci. V takové tabulce se může jeden zaměstnanec hlásit jinému zaměstnanci. Proto můžete použít vlastní spojení ke spojení tabulky ve sloupci ID zaměstnance a ID manažera.
Předpokládejme, že máme následující tabulku:
+--------------+-------------+------------+-------------+ | EmployeeId | FirstName | LastName | ReportsTo | |--------------+-------------+------------+-------------| | 1 | Homer | Connery | NULL | | 2 | Bart | Pitt | 1 | | 3 | Maggie | Griffin | 1 | | 4 | Peter | Farnsworth | 2 | | 5 | Marge | Morrison | NULL | | 6 | Lisa | Batch | 5 | | 7 | Dave | Zuckerberg | 6 | | 8 | Vlad | Cook | 7 | +--------------+-------------+------------+-------------+
Můžeme se sami připojit k tomuto stolu a vrátit všechny zaměstnance a jejich manažery.
SELECT
CONCAT(e1.FirstName, ' ', e1.LastName) AS Employee,
CONCAT(e2.FirstName, ' ', e2.LastName) AS Manager
FROM Employees e1
LEFT JOIN Employees e2
ON e1.ReportsTo = e2.EmployeeId;
Výsledek:
+------------------+-----------------+ | Employee | Manager | |------------------+-----------------| | Homer Connery | | | Bart Pitt | Homer Connery | | Maggie Griffin | Homer Connery | | Peter Farnsworth | Bart Pitt | | Marge Morrison | | | Lisa Batch | Marge Morrison | | Dave Zuckerberg | Lisa Batch | | Vlad Cook | Dave Zuckerberg | +------------------+-----------------+
Další příklady viz SQL Self Join.