SQL JOIN и различные типы соединений
что такое SQL JOIN
а какие бывают разные типы?
7 ответов
что это SQL JOIN
?
SQL JOIN
- это метод извлечения данных из двух или более таблиц базы данных.
какие SQL JOIN
s ?
всего их пять JOIN
s. Они:
1. JOIN or INNER JOIN
2. OUTER JOIN
2.1 LEFT OUTER JOIN or LEFT JOIN
2.2 RIGHT OUTER JOIN or RIGHT JOIN
2.3 FULL OUTER JOIN or FULL JOIN
3. NATURAL JOIN
4. CROSS JOIN
5. SELF JOIN
1. Присоединиться или внутреннее соединение:
в таком виде JOIN
мы получаем все записи, которые соответствуют условию в обеих таблицах, и записи в обеих таблицах, которые не соответствуют не сообщается.
в других слова, INNER JOIN
основано на одном факте: должны быть перечислены только совпадающие записи в обеих таблицах.
обратите внимание, что a JOIN
без каких-либо других JOIN
ключевые слова (например,INNER
, OUTER
, LEFT
и т. д.) - Это INNER JOIN
. Другими словами,JOIN
is
синтаксический сахар для INNER JOIN
(см.: разница между JOIN и INNER JOIN).
2. ВНЕШНЕЕ СОЕДИНЕНИЕ:
OUTER JOIN
получает
либо, совпадающая строка из одной таблицы и всех строк в другой таблице Или, все строки во всех таблицах (неважно, есть ли совпадение или нет).
существует три вида внешнего соединения :
2.1 левое внешнее соединение или левое соединение
этот Join возвращает все строки из левой таблицы в сочетании с соответствующими строками из
правый столик. Если в правой таблице нет совпадающих столбцов, она возвращает NULL
ценности.
2.2 правое внешнее соединение или правое соединение
этой JOIN
возвращает все строки из правой таблицы в сочетании с соответствующими строками из
левая таблица. Если в левой таблице нет совпадающих столбцов, она возвращает NULL
значения.
2.3 полное внешнее соединение или полное соединение
этой JOIN
совместная LEFT OUTER JOIN
и RIGHT OUTER JOIN
. Он возвращает строки из любой таблицы, когда условия встретились и возвращаются NULL
значение, когда нет матча.
другими словами, OUTER JOIN
основано на том, что: должны быть перечислены только совпадающие записи в одной из таблиц (справа или слева) или в обеих таблицах(полных).
Note that `OUTER JOIN` is a loosened form of `INNER JOIN`.
3. ЕСТЕСТВЕННОЕ СОЕДИНЕНИЕ:
он основан на двух условиях:
- на
JOIN
производится на всех столбцах с одинаковым именем для равенства. - удаляет повторяющиеся столбцы результат.
это кажется более теоретическим по своей природе и в результате (вероятно) большинство СУБД даже не утруждайте себя поддержкой.
4. CROSS JOIN:
это декартово произведение двух таблиц. Результат a CROSS JOIN
не будет иметь смысла
в большинстве ситуаций. Более того, нам это вообще не понадобится (или, если быть точным, нужно меньше всего).
5. SELF JOIN:
это не другая форма JOIN
, а это JOIN
(INNER
, OUTER
, etc) таблицы к себе.
присоединяется на основе операторов
в зависимости от оператора, используемого для JOIN
предложение, может быть два типа JOIN
s. Они
- Equi присоединиться
- тета присоединиться
1. Equi JOIN:
на все JOIN
типа (INNER
, OUTER
и т. д.), Если мы используем только оператор равенства ( = ), то мы говорим что
the JOIN
это EQUI JOIN
.
2. Тета присоединиться:
это же EQUI JOIN
но это позволяет всем другим операторам, таким как >, = etc.
многие считают как
EQUI JOIN
и тетаJOIN
аналогичноINNER
,OUTER
и т. д.JOIN
s. Но я твердо верю, что это ошибка и делает идеи расплывчатые. Потому чтоINNER JOIN
,OUTER JOIN
etc все связаны с таблицы и их данные, тогда какEQUI JOIN
иTHETA JOIN
только связано с операторами, которые мы используем в первом.опять же, есть много тех, кто считает
NATURAL JOIN
как какой-то "странно"EQUI JOIN
. На самом деле, это правда, из-за первого условие, которое я упомянул дляNATURAL JOIN
. Однако, мы не должны ограничьте это простоNATURAL JOIN
s в одиночку.INNER JOIN
s,OUTER JOIN
s etc может бытьEQUI JOIN
тоже.
определение:
соединения-это способ запроса данных, которые объединены вместе из нескольких таблиц одновременно.
типы соединений:
к РСУБД относятся 5-типы соединений:
Equi-Join: объединяет общие записи из двух таблиц на основе условия равенства. Технически, объединение производится с помощью оператора равенства ( = ) для сравнения значений PrimaryKey одна таблица и Foriegn Ключевые значения таблицы antoher, следовательно, результирующий набор включает общие (согласованные) записи из обеих таблиц. Для реализации см. INNER-JOIN.
Natural-Регистрация: это расширенная версия Equi-Join, в которой выберите операция пропускает повторяющийся столбец. Для реализации см. INNER-JOIN
Non-Equi-Join: это обратный Equi-join, где условие соединения используется иначе, чем равно оператор (=) e.Джи !=, =, >,
Self-Join:: настраиваемое поведение соединения, где таблица объединена с собой; это обычно необходимо для запроса само-ссылочных таблиц (или унарной сущности отношения). Для реализации см. INNER-JOINs.
Декартова Произведения: он кросс объединяет все записи обеих таблиц без каких-либо условий. Технически он возвращает результирующий набор запроса без предложения WHERE -.
в соответствии с проблемой SQL и продвижением, есть 3 типа соединений, и все соединения СУБД могут быть achvied, используя эти типы соединений.
INNER-JOIN: он объединяет (или комбинирует) совпадающие строки из двух таблиц. Сопоставление выполняется на основе общих столбцов таблиц и операции их сравнения. Если equaility условие тогда: эквисоединение выполняется, в противном случае не EQUI-Join.
-
**OUTER-JOIN: * * он объединяет (или объединяет) совпадающие строки из двух таблиц и непревзойденные строки со значениями NULL. Тем не менее, можно настроить выбор несогласованных строк e.g, выбор непревзойденной строки из первой таблицы или второй таблицы по подтипам: левое внешнее соединение и правое внешнее соединение.
2.1. левое внешнее соединение (a.к. a, left-JOIN): возвращает сопоставленные строки из двух таблиц и не сопоставляется с левой таблицей (i.e, первая таблица) только.
2.2. правое внешнее соединение (a.к. a, RIGHT-JOIN): возвращает сопоставленные строки из двух таблиц и не сопоставленные только из правой таблицы.
2.3. ПОЛНОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ (a.к. A OUTER JOIN): возвращает совпадение и несоответствие из обеих таблиц.
ПЕРЕКРЕСТНОЕ ПРИСОЕДИНЕНИЕ: это соединение не сливается/combiens вместо этого он выполняет cartisian продукт.
Примечание: Self-JOIN может быть достигнуто либо внутренним соединением, либо внешним соединением и перекрестным соединением на основе требования, но таблица должна присоединиться к себе.
примеры:
1.1: INNER-JOIN: Equi-join implemetation
SELECT *
FROM Table1 A
INNER JOIN Table2 B ON A.<PrimaryKey> =B.<ForeignKey>;
1.2: INNER-JOIN: Natural-Регистрация реализации
Select A.*, B.Col1, B.Col2 --But no B.ForiengKyeColumn in Select
FROM Table1 A
INNER JOIN Table2 B On A.Pk = B.Fk;
1.3: внутреннее объединение с Eqijoin реализация
Select *
FROM Table1 A INNER JOIN Table2 B On A.Pk <= B.Fk;
1.4: внутренний-присоединяйтесь к SELF-JOIN
Select *
FROM Table1 A1 INNER JOIN Table1 A2 On A1.Pk = A2.Fk;
2.1: внешнее соединение (полное внешнее соединение)
Select *
FROM Table1 A FULL OUTER JOIN Table2 B On A.Pk = B.Fk;
2.2: СЛЕВА ПРИСОЕДИНИТЬСЯ
Select *
FROM Table1 A LEFT OUTER JOIN Table2 B On A.Pk = B.Fk;
2.3: ПРАВОЕ СОЕДИНЕНИЕ
Select *
FROM Table1 A RIGHT OUTER JOIN Table2 B On A.Pk = B.Fk;
3.1: CROSS JOIN
Select *
FROM TableA CROSS JOIN TableB;
3.2: CROSS JOIN-Self JOIN
Select *
FROM Table1 A1 CROSS JOIN Table1 A2;
//или//
Select *
FROM Table1 A1,Table1 A2;
интересно, что большинство других ответов страдают от этих двух проблем:
- они сосредоточены на основных формах присоединения только
- они (ab)используют диаграммы Венна, которые являются неточным инструментом для визуализации соединений (они намного лучше для Союзов).
недавно я написал статью на эту тему:вероятно, неполное, Полное руководство по многим различным способам объединения таблиц в SQL, которые я суммировать здесь.
прежде всего: соединения являются декартовыми продуктами
вот почему диаграммы Венна объясняют их так неточно, потому что соединение создает декартова произведения между двумя соединенными столами. Википедия прекрасно иллюстрирует это:
синтаксис SQL для декартовых продуктов -CROSS JOIN
. Например:
SELECT *
-- This just generates all the days in January 2017
FROM generate_series(
'2017-01-01'::TIMESTAMP,
'2017-01-01'::TIMESTAMP + INTERVAL '1 month -1 day',
INTERVAL '1 day'
) AS days(day)
-- Here, we're combining all days with all departments
CROSS JOIN departments
который объединяет все строки из одной таблицы со всеми строками с другого стола:--61-->
источник:
+--------+ +------------+
| day | | department |
+--------+ +------------+
| Jan 01 | | Dept 1 |
| Jan 02 | | Dept 2 |
| ... | | Dept 3 |
| Jan 30 | +------------+
| Jan 31 |
+--------+
результат:
+--------+------------+
| day | department |
+--------+------------+
| Jan 01 | Dept 1 |
| Jan 01 | Dept 2 |
| Jan 01 | Dept 3 |
| Jan 02 | Dept 1 |
| Jan 02 | Dept 2 |
| Jan 02 | Dept 3 |
| ... | ... |
| Jan 31 | Dept 1 |
| Jan 31 | Dept 2 |
| Jan 31 | Dept 3 |
+--------+------------+
если мы просто напишем список таблиц, разделенных запятыми, мы получим то же самое:
-- CROSS JOINing two tables:
SELECT * FROM table1, table2
внутреннее соединение (тета-соединение)
An INNER JOIN
это просто отфильтрованный CROSS JOIN
где предикат фильтра называется Theta
в реляционной алгебре.
например:
SELECT *
-- Same as before
FROM generate_series(
'2017-01-01'::TIMESTAMP,
'2017-01-01'::TIMESTAMP + INTERVAL '1 month -1 day',
INTERVAL '1 day'
) AS days(day)
-- Now, exclude all days/departments combinations for
-- days before the department was created
JOIN departments AS d ON day >= d.created_at
обратите внимание, что ключевое слово INNER
является необязательным (за исключением MS Доступ.)
(посмотрите на статью для примеров результатов)
EQUI ПРИСОЕДИНИТЬСЯ
особый вид тета-соединения-это equi JOIN, который мы используем чаще всего. Предикат соединяет первичный ключ одной таблицы с внешним ключом другой таблицы. Если мы используем у sakila базе для иллюстрации можно написать:
SELECT *
FROM actor AS a
JOIN film_actor AS fa ON a.actor_id = fa.actor_id
JOIN film AS f ON f.film_id = fa.film_id
это объединяет всех актеров с их фильмами.
или также, на некоторых базы данных:
SELECT *
FROM actor
JOIN film_actor USING (actor_id)
JOIN film USING (film_id)
на USING()
синтаксис позволяет указать столбец, который должен присутствовать по обе стороны таблиц операции соединения, и создает предикат равенства для этих двух столбцов.
ЕСТЕСТВЕННОЕ СОЕДИНЕНИЕ
другие ответы перечислили этот" тип соединения " отдельно, но это не имеет смысла. Это просто синтаксическая форма сахара для equi JOIN, которая является частным случаем тета-соединения или внутреннего соединения. NATURAL JOIN просто собирает все столбцы, общие для обеих таблиц, которые объединяются и присоединяются USING()
эти столбцы. Что вряд ли когда-либо полезно из-за случайных совпадений (например,LAST_UPDATE
столбцы в у sakila базе).
синтаксис:
SELECT *
FROM actor
NATURAL JOIN film_actor
NATURAL JOIN film
ВНЕШНЕЕ СОЕДИНЕНИЕ
теперь OUTER JOIN
С INNER JOIN
как он создает UNION
несколько декартовым. Мы можем написать:
-- Convenient syntax:
SELECT *
FROM a LEFT JOIN b ON <predicate>
-- Cumbersome, equivalent syntax:
SELECT a.*, b.*
FROM a JOIN b ON <predicate>
UNION ALL
SELECT a.*, NULL, NULL, ..., NULL
FROM a
WHERE NOT EXISTS (
SELECT * FROM b WHERE <predicate>
)
никто не хочет писать второе, так пишем OUTER JOIN
(что обычно лучше оптимизируется базами данных).
как INNER
ключевое слово OUTER
не является обязательным, здесь.
OUTER JOIN
поставляется в трех вариантах:
-
LEFT [ OUTER ] JOIN
: левая таблицаJOIN
выражение добавляется к объединению, как показано выше. -
RIGHT [ OUTER ] JOIN
: правая таблицаJOIN
выражение добавляется к объединению, как показано выше. -
FULL [ OUTER ] JOIN
: обе таблицыJOIN
выражения добавляются в объединение, как показано выше.
все они могут быть объединены с ключевого слова USING()
или NATURAL
(у меня на самом деле был реальный случай использования в мире для NATURAL FULL JOIN
недавно)
альтернативный синтаксис
есть некоторые исторические, устаревшие синтаксисы в Oracle и SQL Server, которые поддерживают OUTER JOIN
уже до стандарта SQL имеет синтаксис:
-- Oracle
SELECT *
FROM actor a, film_actor fa, film f
WHERE a.actor_id = fa.actor_id(+)
AND fa.film_id = f.film_id(+)
-- SQL Server
SELECT *
FROM actor a, film_actor fa, film f
WHERE a.actor_id *= fa.actor_id
AND fa.film_id *= f.film_id
сказав это , не используйте этот синтаксис. Я просто перечисляю это здесь, чтобы вы могли узнать его из старых сообщений в блоге / устаревшего кода.
секционированных OUTER JOIN
мало кто знает об этом, но стандарт SQL указывает секционированный OUTER JOIN
(и Oracle реализует его). Вы можете написать такие вещи:
WITH
-- Using CONNECT BY to generate all dates in January
days(day) AS (
SELECT DATE '2017-01-01' + LEVEL - 1
FROM dual
CONNECT BY LEVEL <= 31
),
-- Our departments
departments(department, created_at) AS (
SELECT 'Dept 1', DATE '2017-01-10' FROM dual UNION ALL
SELECT 'Dept 2', DATE '2017-01-11' FROM dual UNION ALL
SELECT 'Dept 3', DATE '2017-01-12' FROM dual UNION ALL
SELECT 'Dept 4', DATE '2017-04-01' FROM dual UNION ALL
SELECT 'Dept 5', DATE '2017-04-02' FROM dual
)
SELECT *
FROM days
LEFT JOIN departments
PARTITION BY (department) -- This is where the magic happens
ON day >= created_at
части результата:
+--------+------------+------------+
| day | department | created_at |
+--------+------------+------------+
| Jan 01 | Dept 1 | | -- Didn't match, but still get row
| Jan 02 | Dept 1 | | -- Didn't match, but still get row
| ... | Dept 1 | | -- Didn't match, but still get row
| Jan 09 | Dept 1 | | -- Didn't match, but still get row
| Jan 10 | Dept 1 | Jan 10 | -- Matches, so get join result
| Jan 11 | Dept 1 | Jan 10 | -- Matches, so get join result
| Jan 12 | Dept 1 | Jan 10 | -- Matches, so get join result
| ... | Dept 1 | Jan 10 | -- Matches, so get join result
| Jan 31 | Dept 1 | Jan 10 | -- Matches, so get join result
дело в том, что все строки с секционированной стороны соединения будут заканчиваться в результате независимо от того, JOIN
соответствует чему-либо на "другой стороне соединения". Короче говоря, это заполнение разреженных данных в отчетах. Очень полезно!
SEMI JOIN
серьезно? Другого ответа не было? Конечно, нет!--168-->потому что у него нет собственного синтаксиса в SQL, к сожалению (так же, как ANTI JOIN ниже). Но мы можем использовать IN()
и EXISTS()
, например, чтобы найти всех актеров, которые играли в фильмах:
SELECT *
FROM actor a
WHERE EXISTS (
SELECT * FROM film_actor fa
WHERE a.actor_id = fa.actor_id
)
на WHERE a.actor_id = fa.actor_id
сказуемое выступает в качестве предикат semi join. Если вы не верите в это, ознакомьтесь с планами выполнения, например, в Oracle. Вы увидите, что база данных выполняет операцию ПОЛУСОЕДИНЕНИЯ, а не EXISTS()
сказуемое.
АНТИ ПРИСОЕДИНИТЬСЯ
это как раз противоположность SEMI JOIN (будьте осторожны, чтобы не использовать NOT IN
хотя, так как имеет важное предостережение)
вот все актеры без фильмы:
SELECT *
FROM actor a
WHERE NOT EXISTS (
SELECT * FROM film_actor fa
WHERE a.actor_id = fa.actor_id
)
некоторые люди (особенно люди MySQL) также пишут ANTI JOIN следующим образом:
SELECT *
FROM actor a
LEFT JOIN film_actor fa
USING (actor_id)
WHERE film_id IS NULL
я думаю, что историческая причина-производительность.
БОКОВОЕ СОЕДИНЕНИЕ
OMG, это слишком круто. Я единственный, кто упомянул об этом? Вот классный запрос:
SELECT a.first_name, a.last_name, f.*
FROM actor AS a
LEFT OUTER JOIN LATERAL (
SELECT f.title, SUM(amount) AS revenue
FROM film AS f
JOIN film_actor AS fa USING (film_id)
JOIN inventory AS i USING (film_id)
JOIN rental AS r USING (inventory_id)
JOIN payment AS p USING (rental_id)
WHERE fa.actor_id = a.actor_id -- JOIN predicate with the outer query!
GROUP BY f.film_id
ORDER BY revenue DESC
LIMIT 5
) AS f
ON true
он найдет 5 лучших доходов, производящих фильмы на одного актера. Каждый раз, когда вам нужен запрос TOP-N-per-something,LATERAL JOIN
будет вашим другом. Если вы SQL Серверный человек, тогда вы знаете это JOIN
тип под ником APPLY
SELECT a.first_name, a.last_name, f.*
FROM actor AS a
OUTER APPLY (
SELECT f.title, SUM(amount) AS revenue
FROM film AS f
JOIN film_actor AS fa ON f.film_id = fa.film_id
JOIN inventory AS i ON f.film_id = i.film_id
JOIN rental AS r ON i.inventory_id = r.inventory_id
JOIN payment AS p ON r.rental_id = p.rental_id
WHERE fa.actor_id = a.actor_id -- JOIN predicate with the outer query!
GROUP BY f.film_id
ORDER BY revenue DESC
LIMIT 5
) AS f
хорошо, возможно, это обман, потому что LATERAL JOIN
или APPLY
выражение действительно является "коррелированным подзапросом", который создает несколько строк. Но если мы допустим "коррелированные подзапросы", мы также можем говорить об этом...
MULTISET
это действительно реализовано только Oracle и Informix (насколько мне известно), но его можно эмулировать в PostgreSQL с использованием массивов и / или XML и в SQL Server с использованием XML.
MULTISET
создает коррелированный подзапрос и помещает результирующий набор строк во внешний запрос. Запрос ниже выбирает всех актеров и для каждого актера собирает свои фильмы во вложенную коллекцию:
SELECT a.*, MULTISET (
SELECT f.*
FROM film AS f
JOIN film_actor AS fa USING (film_id)
WHERE a.actor_id = fa.actor_id
) AS films
FROM actor
как вы видели, есть больше типов соединения, чем просто "скучно"INNER
, OUTER
и CROSS JOIN
это обычно упоминается. подробнее в моей статье. И, пожалуйста, прекратите использовать диаграммы Venn для иллюстрации их.
в SQL server существуют различные типы соединений.
- КРЕСТ ПРИСОЕДИНИТЬСЯ
- ВНУТРЕННЕЕ СОЕДИНЕНИЕ
- ВНЕШНЕЕ СОЕДИНЕНИЕ
внешние соединения снова делятся на 3 типа
- левое соединение или левое внешнее соединение
- правое соединение или правое внешнее соединение
- полное соединение или полный внешний Присоединяйтесь
JOIN или внутреннее соединение
SELECT Name, Gender, Salary, DepartmentName
FROM tblEmployee
INNER JOIN tblDepartment
ON tblEmployee.DepartmentId = tblDepartment.Id
OR
SELECT Name, Gender, Salary, DepartmentName
FROM tblEmployee
JOIN tblDepartment
ON tblEmployee.DepartmentId = tblDepartment.Id
левое соединение или левое внешнее соединение
SELECT Name, Gender, Salary, DepartmentName
FROM tblEmployee
LEFT OUTER JOIN tblDepartment
ON tblEmployee.DepartmentId = tblDepartment.Id
OR
SELECT Name, Gender, Salary, DepartmentName
FROM tblEmployee
LEFT JOIN tblDepartment
ON tblEmployee.DepartmentId = tblDepartment.Id
правое соединение или правое внешнее соединение
SELECT Name, Gender, Salary, DepartmentName
FROM tblEmployee
RIGHT OUTER JOIN tblDepartment
ON tblEmployee.DepartmentId = tblDepartment.Id
OR
SELECT Name, Gender, Salary, DepartmentName
FROM tblEmployee
RIGHT JOIN tblDepartment
ON tblEmployee.DepartmentId = tblDepartment.Id
полное соединение или полный внешний Присоединяйтесь
SELECT Name, Gender, Salary, DepartmentName
FROM tblEmployee
FULL OUTER JOIN tblDepartment
ON tblEmployee.DepartmentId = tblDepartment.Id
OR
SELECT Name, Gender, Salary, DepartmentName
FROM tblEmployee
FULL JOIN tblDepartment
ON tblEmployee.DepartmentId = tblDepartment.Id
Я собираюсь нажать мой питомец peeve: ключевое слово USING.
если обе таблицы с обеих сторон соединения имеют свои внешние ключи с правильным именем (т. е. с тем же именем, а не только " id), то это можно использовать:
SELECT ...
FROM customers JOIN orders USING (customer_id)
Я нахожу это очень практичным, читаемым и недостаточно часто используемым.