Синтаксис SQL INNER JOIN

два бита SQL ниже дают одинаковый результат

SELECT c.name, o.product  
FROM customer c, order o  
WHERE c.id = o.cust_id  
AND o.value = 150  

SELECT c.name, o.product  
FROM customer c  
INNER JOIN order o on c.id = o.cust_id  
WHERE o.value = 150

Я видел, что оба стиля используются как стандартные в разных компаниях. Из того, что я видел, второй вариант - это то, что большинство людей рекомендуют в Интернете. Есть ли для этого какая-то реальная причина, кроме стиля? Иногда ли использование внутреннего соединения дает лучшую производительность?

Я заметил, что разработчики Ingres и Oracle склонны использовать первый стиль, тогда как пользователи Microsoft SQL Server склонны использовать второй, но это может быть просто совпадением.

Спасибо за понимание, я задумывался об этом некоторое время.

Обновлено: я изменил название с «Внутреннее соединение SQL по сравнению с декартовым продуктом», поскольку я использовал неправильную терминологию. Спасибо за все ответы.

ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
28
0
28 799
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Оба запроса выполняют внутреннее соединение, просто разный синтаксис.

На самом деле эти примеры эквивалентны и не являются декартовым произведением. Декартово произведение возвращается, когда вы соединяете две таблицы без указания условия соединения, например, в

select *
from t1,t2

Это хорошее обсуждение на Википедия.

Чтобы ответить на часть вашего вопроса, я думаю, что ранние ошибки в синтаксисе JOIN ... ON в Oracle отговаривали пользователей Oracle от этого синтаксиса. Не думаю, что сейчас есть какие-то особые проблемы.

Они эквивалентны и должны быть проанализированы в одном и том же внутреннем представлении для оптимизации.

Некоторые ошибки в синтаксисе ANSI JOIN не являются тем, что я бы назвал «ранними». На предыдущей работе, когда мы выполняли много огромных запросов, мы столкнулись с жестким ограничением на количество общих столбцов, которые вы могли бы иметь в запросе, если бы вы использовали синтаксис ANSI JOIN. Вы обнаружите, что, по крайней мере, до выпуска 10g все еще были проблемы.

Nate C-K 28.08.2012 16:56

Да, я до сих пор не использую соединения ANSI.

WW. 28.08.2012 17:41

Oracle опоздал с поддержкой синтаксиса JOIN ... ON (ANSI) (не раньше Oracle 9), поэтому разработчики Oracle часто его не используют.

Лично я предпочитаю использовать синтаксис ANSI, когда логически ясно, что одна таблица управляет запросом, а другие являются таблицами поиска. Когда таблицы «равны», я обычно использую декартово синтаксис.

Спектакль вообще не должен отличаться.

Ответ принят как подходящий

Оба запроса являются внутренними соединениями и эквивалентами. Первый - это более старый метод работы, тогда как использование синтаксиса JOIN стало обычным явлением только после введения стандарта SQL-92 (я считаю, что он в старых определениях просто не использовался особенно широко до этого).

Использование синтаксиса JOIN настоятельно рекомендуется, поскольку оно отделяет логику соединения от логики фильтрации в предложении WHERE. Хотя синтаксис JOIN на самом деле является синтаксическим сахаром для внутренних соединений, его сила заключается во внешних соединениях, где старый синтаксис * может создавать ситуации, когда невозможно однозначно описать соединение, а интерпретация зависит от реализации. [ЛЕВЫЙ | RIGHT] Синтаксис JOIN позволяет избежать этих ловушек, и, следовательно, для единообразия использование предложения JOIN предпочтительнее при любых обстоятельствах.

Обратите внимание, что ни один из этих двух примеров не является декартовым произведением. Для этого вы бы использовали либо

SELECT c.name, o.product  
FROM customer c, order o  
WHERE o.value = 150  

или же

SELECT c.name, o.product  
FROM customer c  CROSS JOIN order o 
WHERE o.value = 150

Обозначение JOIN было введено в SQL-92; это стало распространенным явлением намного позже.

Jonathan Leffler 28.12.2008 00:52

Спасибо за исправление, я проверил, смогу ли найти дату. Лично я действительно перешел на использование JOINS только в 2001 или 2 - сначала мне показалось, что это использование немного странно, но сейчас я предпочитаю его.

Cruachan 28.12.2008 13:28

Не могли бы вы привести пример такой ситуации, когда старый синтаксис обязательно неоднозначен? Спасибо.

Evgeniy 04.12.2019 21:48

Синтаксис JOIN ... ON ... является более поздним дополнением к спецификациям ANSI и ISO для SQL. Синтаксис JOIN ... ON ... обычно предпочтительнее, потому что он 1) перемещает критерии соединения из предложения WHERE, делая предложение WHERE только для фильтрации и 2) делает его более очевидным, если вы создаете ужасный декартово произведение, поскольку каждый JOIN должен сопровождаться как минимум одним предложением ON. Если все критерии соединения просто AND в предложении WHERE, это не так очевидно, когда один или несколько пропущены.

TL; DR

Оператор INNER JOIN можно переписать как CROSS JOIN с предложением WHERE, совпадающим с тем же условием, которое вы использовали в предложении ON запроса INNER JOIN.

Связь между таблицами

Учитывая, что у нас есть следующие таблицы post и post_comment:

The post and post_comment tables

post имеет следующие записи:

| id | title     |
|----|-----------|
| 1  | Java      |
| 2  | Hibernate |
| 3  | JPA       |

а post_comment имеет следующие три ряда:

| id | review    | post_id |
|----|-----------|---------|
| 1  | Good      | 1       |
| 2  | Excellent | 1       |
| 3  | Awesome   | 2       |

SQL ВНУТРЕННЕЕ СОЕДИНЕНИЕ

Предложение SQL JOIN позволяет связывать строки, принадлежащие разным таблицам. Например, КРЕСТНОЕ СОЕДИНЕНИЕ создаст декартово произведение, содержащее все возможные комбинации строк между двумя соединяемыми таблицами.

Хотя CROSS JOIN полезен в определенных сценариях, в большинстве случаев вы хотите объединить таблицы на основе определенного условия. И вот здесь в игру вступает INNER JOIN.

SQL INNER JOIN позволяет нам фильтровать декартово произведение объединения двух таблиц на основе условия, указанного в предложении ON.

SQL INNER JOIN - ON условие "всегда верно"

Если вы предоставите условие «всегда верно», INNER JOIN не будет фильтровать объединенные записи, и набор результатов будет содержать декартово произведение двух объединяемых таблиц.

Например, если мы выполним следующий запрос SQL INNER JOIN:

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
INNER JOIN post_comment pc ON 1 = 1

Мы получим все комбинации записей post и post_comment:

| p.id    | pc.id      |
|---------|------------|
| 1       | 1          |
| 1       | 2          |
| 1       | 3          |
| 2       | 1          |
| 2       | 2          |
| 2       | 3          |
| 3       | 1          |
| 3       | 2          |
| 3       | 3          |

Итак, если условие предложения ON "всегда истинно", INNER JOIN просто эквивалентно запросу CROSS JOIN:

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
CROSS JOIN post_comment
WHERE 1 = 1
ORDER BY p.id, pc.id

SQL INNER JOIN - ON условие "всегда ложно"

С другой стороны, если условие предложения ON «всегда ложно», то все объединенные записи будут отфильтрованы, и набор результатов будет пустым.

Итак, если мы выполним следующий запрос SQL INNER JOIN:

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
INNER JOIN post_comment pc ON 1 = 0
ORDER BY p.id, pc.id

Никакого результата назад мы не получим:

| p.id    | pc.id      |
|---------|------------|

Это потому, что приведенный выше запрос эквивалентен следующему запросу CROSS JOIN:

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
CROSS JOIN post_comment
WHERE 1 = 0
ORDER BY p.id, pc.id

SQL INNER JOIN - предложение ON с использованием столбцов внешнего ключа и первичного ключа

Наиболее распространенное условие предложения ON - это то, которое сопоставляет столбец внешнего ключа в дочерней таблице со столбцом первичного ключа в родительской таблице, как показано в следующем запросе:

SELECT
   p.id AS "p.id",
   pc.post_id AS "pc.post_id",
   pc.id AS "pc.id",
   p.title AS "p.title",
   pc.review  AS "pc.review"
FROM post p
INNER JOIN post_comment pc ON pc.post_id = p.id
ORDER BY p.id, pc.id

При выполнении вышеуказанного запроса SQL INNER JOIN мы получаем следующий набор результатов:

| p.id    | pc.post_id | pc.id      | p.title    | pc.review |
|---------|------------|------------|------------|-----------|
| 1       | 1          | 1          | Java       | Good      |
| 1       | 1          | 2          | Java       | Excellent |
| 2       | 2          | 3          | Hibernate  | Awesome   |

Таким образом, в набор результатов запроса включаются только записи, соответствующие условию предложения ON. В нашем случае набор результатов содержит все post вместе с их записями post_comment. Строки post, не связанные с post_comment, исключаются, поскольку они не могут удовлетворять условию предложения ON.

Опять же, приведенный выше запрос SQL INNER JOIN эквивалентен следующему запросу CROSS JOIN:

SELECT
   p.id AS "p.id",
   pc.post_id AS "pc.post_id",
   pc.id AS "pc.id",
   p.title AS "p.title",
   pc.review  AS "pc.review"
FROM post p, post_comment pc
WHERE pc.post_id = p.id

Незачеркнутые строки удовлетворяют условию WHERE, и только эти записи будут включены в набор результатов. Это лучший способ визуализировать, как работает предложение INNER JOIN.

| p.id | pc.post_id | pc.id | p.title   | pc.review |
|------|------------|-------|-----------|-----------|
| 1    | 1          | 1     | Java      | Good      |
| 1    | 1          | 2     | Java      | Excellent |
| 1    | 2          | 3     | Java      | Awesome   || 2    | 1          | 1     | Hibernate | Good      || 2    | 1          | 2     | Hibernate | Excellent |
| 2    | 2          | 3     | Hibernate | Awesome   |
| 3    | 1          | 1     | JPA       | Good      || 3    | 1          | 2     | JPA       | Excellent || 3    | 2          | 3     | JPA       | Awesome   |

Not that this only applies to INNER JOIN, not for OUTER JOIN.

Ограничения не имеют отношения к определению соединения, поэтому упоминание их до тех пор, пока не будет объяснено, как работает соединение, вводит в заблуждение.

philipxy 08.04.2020 00:48

Я не думаю, что это вводит в заблуждение.

Vlad Mihalcea 08.04.2020 07:54

Другие вопросы по теме