SQL присъединяването е мястото, където изпълнявате заявка, която обединява множество таблици.
Този урок за SQL присъединяване представя основни примери за SQL присъединявания, както и въведение в различните типове присъединяване.
Типове на присъединяване към SQL
Стандартът ANSI SQL определя пет типа обединения, както е изброено в следващата таблица.
Тип на присъединяване | Описание |
---|---|
INNER JOIN | Връща редове, когато има поне един ред и в двете таблици, който отговаря на условието за присъединяване. |
LEFT OUTER JOIN или LEFT JOIN | Връща редове, които имат данни в лявата таблица (вляво от JOIN ключова дума), дори ако няма съвпадащи редове в дясната таблица. |
RIGHT OUTER JOIN или RIGHT JOIN | Връща редове, които имат данни в дясната таблица (вдясно от JOIN ключова дума), дори ако в лявата таблица няма съвпадащи редове. |
FULL OUTER JOIN или FULL JOIN | Връща всички редове, стига да има съвпадащи данни в една от таблиците. |
CROSS JOIN | Връща редове, които комбинират всеки ред от първата таблица с всеки ред от втората таблица. |
Съществуват и други термини за различни операции за присъединяване, като например следните:
Присъединете се | Описание |
---|---|
Самоприсъединяване | Когато таблица се присъедини към себе си. |
Естествено присъединяване | Неявно присъединяване, базирано на общите колони в двете таблици, които се свързват. |
Екви-съединяване | Обединение, съдържащо само сравнения на равенство в предиката на присъединяване. |
Синтаксис за присъединяване към SQL
Вътрешните съединения могат да бъдат посочени или в FROM
или WHERE
клаузи. Външните и кръстосаните съединения могат да бъдат посочени в FROM
само клауза.
За да създадете SQL присъединяване в FROM
клауза, направете нещо подобно:
SELECT *
FROM Table1 < JoinType > Table2 [ ON ( JoinCondition ) ]
Където JoinType
указва какъв вид присъединяване се извършва и JoinCondition
дефинира предиката, който да бъде оценен за всяка двойка съединени редове.
За да посочите присъединяване в WHERE
клауза, направете нещо подобно:
SELECT *
FROM Table1, Table2 [ WHERE ( JoinCondition ) ]
Отново JoinCondition
дефинира предиката, който да бъде оценен за всяка двойка съединени редове.
Също така всичко, оградено в квадратни скоби ([]
) е по избор.
Примерни таблици за примерите в този урок
Повечето от примерите в този урок изпълняват обединявания срещу следните две таблици.
PetTypes
таблица:
+------------+-----------+| PetTypeId | PetType ||-------------+-----------|| 1 | Птица || 2 | Котка || 3 | Куче || 4 | Заек |+------------+-----------+(4 реда засегнати)
Pets
таблица:
+--------+------------+-----------+---------- -+-----------+| PetId | PetTypeId | Id на собственик | Име на домашни любимци | DOB ||---------+------------+-----------+----------- +-----------|| 1 | 2 | 3 | Пухкави | 20.11.2020 || 2 | 3 | 3 | Вземи | 2019-08-16 || 3 | 2 | 2 | Надраскване | 01.10.2018 || 4 | 3 | 3 | Размахване | 2020-03-15 || 5 | 1 | 1 | Tweet | 28.11.2020 || 6 | 3 | 4 | Пухкави | 17.09.2020 || 7 | 3 | 2 | Кора | NULL || 8 | 2 | 4 | Мяу | NULL |+--------+------------+-----------+----------- +-----------+(8 засегнати реда)
Вътрешното съединение
SQL INNER JOIN
връща редове, когато има поне един ред и в двете таблици, който отговаря на условието за присъединяване.
SELECT
Pets.PetName,
PetTypes.PetType
FROM Pets
INNER JOIN PetTypes
ON Pets.PetTypeId = PetTypes.PetTypeId;
Резултат:
-----------+-----------+| Име на домашни любимци | PetType ||-----------+-----------|| Пухкави | Котка || Вземи | Куче || Надраскване | Котка || Размахване | Куче || Tweet | Птица || Пухкави | Куче || Кора | Куче || Мяу | Котка |+-----------+-----------+(8 реда засегнати)
За да посочите вътрешно присъединяване в FROM
клауза, ние използваме INNER JOIN
. Ние също така използваме ON
ключова дума за дефиниране на предиката, който да бъде оценен за всяка двойка съединени редове.
Независимо от типа на присъединяването, ние квалифицираме имената на колоните си с имената на таблиците. Причината да правим това е, за да избегнем неясноти по отношение на имената на колоните между таблиците. И двете таблици могат да имат колони с едно и също име (както в нашия пример) и в такива случаи СУБД няма да знае коя колона имате предвид. Поставянето на префикс на имената на колоните с имената на техните таблици гарантира, че препращате към дясната колона и предотвратява всякакви грешки, които биха могли да възникнат от неяснота относно това коя колона имате предвид.
В този пример и двете таблици имат PetTypeId
колона. Pets.PetTypeId
колоната е външен ключ към PetTypes.PetTypeId
колона, която е първичният ключ за тази таблица.
В този пример можем да видим, че всички домашни любимци са върнати, но не всички видове домашни любимци са върнати. В Pets
няма зайци таблицата и така Rabbits
тип домашни любимци не се връща.
Причината Rabbits
типът не се връща, защото INNER JOIN
връща редове само когато има поне един ред и в двете таблици, който отговаря на условието за присъединяване. В този случай Rabbits
е само в една таблица (PetTypes
таблица).
Имайте предвид, че типът на присъединяване не е задължителен. Следователно повечето (ако не всички) СУБД ви позволяват да пропуснете INNER
ключова дума. Когато пропуснете това (т.е. посочете само JOIN
), се приема, че е вътрешно съединение.
Следователно бихме могли да пренапишем горния пример на това:
SELECT
Pets.PetName,
PetTypes.PetType
FROM Pets
JOIN PetTypes
ON Pets.PetTypeId = PetTypes.PetTypeId;
Също така, както при всеки SQL израз, FROM
клаузата може да бъде на един цял ред, ако предпочитате:
SELECT
Pets.PetName,
PetTypes.PetType
FROM Pets JOIN PetTypes ON Pets.PetTypeId = PetTypes.PetTypeId;
Псевдоними
Обичайна практика е да се използват псевдоними на таблици, когато се извършват SQL присъединявания. Псевдонимите помагат да направите кода по-сбит и по-лесен за четене.
Следователно бихме могли да променим предишния пример на този:
SELECT
p.PetName,
pt.PetType
FROM Pets p INNER JOIN PetTypes pt
ON p.PetTypeId = pt.PetTypeId;
Резултат:
-----------+-----------+| Име на домашни любимци | PetType ||-----------+-----------|| Пухкави | Котка || Вземи | Куче || Надраскване | Котка || Размахване | Куче || Tweet | Птица || Пухкави | Куче || Кора | Куче || Мяу | Котка |+-----------+-----------+(8 реда засегнати)
The Equi-Join
Горното присъединяване може също да се нарича equi-join . Equi-join е съединение, съдържащо само сравнения на равенство в предиката на присъединяване.
Друг начин за писане на горното присъединяване е така:
SELECT
p.PetName,
pt.PetType
FROM
Pets p,
PetTypes pt
WHERE p.PetTypeId = pt.PetTypeId;
Резултат:
+-----------+-----------+| Име на домашни любимци | PetType ||-----------+-----------|| Пухкави | Котка || Вземи | Куче || Надраскване | Котка || Размахване | Куче || Tweet | Птица || Пухкави | Куче || Кора | Куче || Мяу | Котка |+-----------+-----------+
Това е пример за определяне на вътрешно присъединяване в WHERE
клауза. Просто предоставихме разделен със запетая списък на таблиците и след това WHERE
състояние. Ако сме пропуснали WHERE
условие, щяхме да завършим с CROSS JOIN
.
Много начинаещи намират горния синтаксис за много по-лесен за разбиране от INNER JOIN
синтаксис. Чувствайте се свободни да използвате този синтаксис, ако предпочитате, но имайте предвид, че повечето специалисти по SQL предпочитат да използват INNER JOIN
синтаксис от предишния пример.
Вижте SQL Inner Join за повече примери, включително вътрешно свързване, което свързва 3 таблици.
Правилното присъединяване
Известен също като RIGHT OUTER JOIN
, RIGHT JOIN
връща редове, които имат данни в дясната таблица (вдясно от JOIN
ключова дума), дори ако в лявата таблица няма съвпадащи редове.
SELECT
p.PetName,
pt.PetType
FROM Pets p
RIGHT JOIN PetTypes pt
ON p.PetTypeId = pt.PetTypeId;
Резултат:
+-----------+-----------+| Име на домашни любимци | PetType ||-----------+-----------|| Tweet | Птица || Пухкави | Котка || Надраскване | Котка || Мяу | Котка || Вземи | Куче || Размахване | Куче || Пухкави | Куче || Кора | Куче || NULL | Заек |+-----------+-----------+(9 реда засегнати)
В този случай имаме допълнителен PetType
стойност – Rabbit
– въпреки че в Pets
няма домашен любимец таблица от този тип. Това води до NULL
стойност в PetName
колона срещу Rabbit
.
Вижте SQL Right Join за повече примери, включително дясно присъединяване, което свързва 3 таблици.
Лявото присъединяване
Известен също като LEFT OUTER JOIN
, SQL LEFT JOIN
връща редове, които имат данни в лявата таблица (вляво от JOIN
ключова дума), дори ако в дясната таблица няма съвпадащи редове.
Това е обратното на RIGHT JOIN
.
Ако променим предишния пример, за да използваме ляво присъединяване, получаваме следния резултат.
SELECT
p.PetName,
pt.PetType
FROM Pets p
LEFT JOIN PetTypes pt
ON p.PetTypeId = pt.PetTypeId;
Резултат:
+-----------+-----------+| Име на домашни любимци | PetType ||-----------+-----------|| Пухкави | Котка || Вземи | Куче || Надраскване | Котка || Размахване | Куче || Tweet | Птица || Пухкави | Куче || Кора | Куче || Мяу | Котка |+-----------+-----------+(8 реда засегнати)
В този конкретен случай нашите резултати са същите като при вътрешното съединение.
Ако обаче сменим реда на таблицата в нашия FROM
клауза, ще получим подобен резултат за дясното присъединяване в предишния пример.
SELECT
p.PetName,
pt.PetType
FROM PetTypes pt
LEFT JOIN Pets p
ON p.PetTypeId = pt.PetTypeId;
Резултат:
+-----------+-----------+| Име на домашни любимци | PetType ||-----------+-----------|| Tweet | Птица || Пухкави | Котка || Надраскване | Котка || Мяу | Котка || Вземи | Куче || Размахване | Куче || Пухкави | Куче || Кора | Куче || NULL | Заек |+-----------+-----------+(9 реда засегнати)
Така че можете да видите, че всяка получена разлика между лявото и дясното свързване зависи единствено от това как подреждате колоните в FROM
клауза.
Вижте SQL Left Join за повече примери, включително ляво присъединяване, което свързва 3 таблици.
Пълното присъединяване
SQL FULL JOIN
(или FULL OUTER JOIN
) връща всички редове, стига да има съвпадащи данни в една от таблиците.
С други думи, това е като да имате и ляво, и дясно присъединяване в едно присъединяване.
Ето пример за пълно присъединяване.
SELECT
p.PetName,
pt.PetType
FROM Pets p
FULL JOIN PetTypes pt
ON p.PetTypeId = pt.PetTypeId;
Резултат:
+-----------+-----------+| Име на домашни любимци | PetType ||-----------+-----------|| Пухкави | Котка || Вземи | Куче || Надраскване | Котка || Размахване | Куче || Tweet | Птица || Пухкави | Куче || Кора | Куче || Мяу | Котка || NULL | Заек |+-----------+-----------+(9 реда засегнати)
Това връща същия резултат, който получихме с дясното присъединяване, но би върнал различен резултат, ако имаше ред в лявата таблица, който нямаше съответната стойност в дясната таблица.
Нека разменим имената на таблиците и да я стартираме отново.
SELECT
p.PetName,
pt.PetType
FROM PetTypes pt
FULL JOIN Pets p
ON p.PetTypeId = pt.PetTypeId;
Резултат:
+-----------+-----------+| Име на домашни любимци | PetType ||-----------+-----------|| Tweet | Птица || Пухкави | Котка || Надраскване | Котка || Мяу | Котка || Вземи | Куче || Размахване | Куче || Пухкави | Куче || Кора | Куче || NULL | Заек |+-----------+-----------+(9 реда засегнати)
Същият резултат.
Вижте Пълно присъединяване на SQL за повече примери, включително пълно присъединяване, което свързва 3 таблици.
Кръстосаното присъединяване
SQL CROSS JOIN
връща редове, които комбинират всеки ред от първата таблица с всеки ред от втората таблица.
С други думи, той връща декартовото произведение на редовете от таблици в обединението.
SELECT
p.PetName,
pt.PetType
FROM Pets p
CROSS JOIN PetTypes pt;
Резултат:
+-----------+-----------+| Име на домашни любимци | PetType ||-----------+-----------|| Пухкави | Птица || Вземи | Птица || Надраскване | Птица || Размахване | Птица || Tweet | Птица || Пухкави | Птица || Кора | Птица || Мяу | Птица || Пухкави | Котка || Вземи | Котка || Надраскване | Котка || Размахване | Котка || Tweet | Котка || Пухкави | Котка || Кора | Котка || Мяу | Котка || Пухкави | Куче || Вземи | Куче || Надраскване | Куче || Размахване | Куче || Tweet | Куче || Пухкави | Куче || Кора | Куче || Мяу | Куче || Пухкави | Заек || Вземи | Заек || Надраскване | Заек || Размахване | Заек || Tweet | Заек || Пухкави | Заек || Кора | Заек || Мяу | Заек |+-----------+-----------+(32 реда засегнати)
Както вероятно можете да си представите, това може да бъде много опасно, ако го стартирате срещу грешни таблици.
Това е същото като да направите това:
SELECT
p.PetName,
pt.PetType
FROM Pets p, PetTypes pt;
Можете да добавите WHERE
клауза към кръстосано съединение, което ще го превърне във вътрешно съединение.
Като това:
SELECT
p.PetName,
pt.PetType
FROM Pets p
CROSS JOIN PetTypes pt
WHERE p.PetTypeId = pt.PetTypeId;
Резултат:
+-----------+-----------+| Име на домашни любимци | PetType ||-----------+-----------|| Пухкави | Котка || Вземи | Куче || Надраскване | Котка || Размахване | Куче || Tweet | Птица || Пухкави | Куче || Кора | Куче || Мяу | Котка |+-----------+-----------+(8 реда засегнати)
Вижте SQL Cross Join за повече примери.
Естественото присъединяване
SQL NATURAL JOIN
е тип equi-join, при който предикатът за присъединяване възниква имплицитно чрез сравняване на всички колони в двете таблици, които имат еднакви имена на колони в обединените таблици.
Резултатът съдържа само една колона за всяка двойка колони с еднакво име. Ако не бъдат намерени колони със същите имена, резултатът ще бъде кръстосано свързване.
SELECT
Pets.PetName,
PetTypes.PetType
FROM Pets NATURAL JOIN PetTypes;
Резултат:
<предварително име на домашен любимец | домашни любимци ---------+-------- Пухкави | Извличане на котка | Кучешка драскотина | Котешко размахване | Куче Туит | Bird Fluffy | Кучешки лай | Куче Мяу | Котка (8 реда)Всъщност естественото присъединяване всъщност не е тип присъединяване, както се счита от стандарта ANSI. Това е ключова дума, която можете да вмъкнете по избор, за да направите присъединяването естествено.
Следователно бихме могли да променим горния пример на NATURAL INNER JOIN
ако искаме:
SELECT
Pets.PetName,
PetTypes.PetType
FROM Pets NATURAL INNER JOIN PetTypes;
Както споменахме по-рано, вътрешните съединения са типът на присъединяване по подразбиране, така че ако пропуснете типа на присъединяване (напр. INNER
, LEFT
, RIGHT
и т.н.), след което се третира като вътрешно съединение.
Ако форматирането на тези резултати изглежда различно от предишните резултати, това е защото трябваше да прескоча към PostgreSQL, за да изпълня тази заявка. Пуснах предишните примери в SQL Server, но SQL Server не поддържа естественото присъединяване.
Вижте SQL Natural Join за повече примери, включително естествено присъединяване, което свързва 3 таблици.
Самоприсъединяването
SQL SELF JOIN
присъединява маса към себе си.
Класически пример за самостоятелно присъединяване е в таблица на служителите. В такава таблица един служител може да докладва на друг служител. Следователно, можете да използвате самостоятелно присъединяване, за да се присъедините към таблицата в колоната за идентификационен номер на служител и колоната с идентификационен номер на мениджър.
Да предположим, че имаме следната таблица:
+--------------+------------+------------+---- ---------+| EmployeeId | Име | Фамилия | Доклади до ||--------------+------------+------------+----- --------|| 1 | Омир | Конъри | NULL || 2 | Барт | Пит | 1 || 3 | Маги | Грифин | 1 || 4 | Петър | Фарнсуърт | 2 || 5 | Мардж | Морисън | NULL || 6 | Лиза | Партида | 5 || 7 | Дейв | Зукърбърг | 6 || 8 | Влад | Готви | 7 |+--------------+------------+------------+----- --------+
Можем да направим самостоятелно присъединяване към тази маса, за да върнем всички служители и техните мениджъри.
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;
Резултат:
+-----------------+----------------+| Служител | Мениджър ||-----------------+----------------|| Хоумър Конъри | || Барт Пит | Хоумър Конъри || Маги Грифин | Хоумър Конъри || Питър Фарнсуърт | Барт Пит || Мардж Морисън | || Лиза Бач | Мардж Морисън || Дейв Зукърбърг | Лиза Бач || Влад Кук | Дейв Зукърбърг |+-----------------+----------------+
Вижте SQL Self Join за повече примери.