два бита 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 по сравнению с декартовым продуктом», поскольку я использовал неправильную терминологию. Спасибо за все ответы.


Оба запроса выполняют внутреннее соединение, просто разный синтаксис.
На самом деле эти примеры эквивалентны и не являются декартовым произведением. Декартово произведение возвращается, когда вы соединяете две таблицы без указания условия соединения, например, в
select *
from t1,t2
Это хорошее обсуждение на Википедия.
Чтобы ответить на часть вашего вопроса, я думаю, что ранние ошибки в синтаксисе JOIN ... ON в Oracle отговаривали пользователей Oracle от этого синтаксиса. Не думаю, что сейчас есть какие-то особые проблемы.
Они эквивалентны и должны быть проанализированы в одном и том же внутреннем представлении для оптимизации.
Да, я до сих пор не использую соединения ANSI.
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; это стало распространенным явлением намного позже.
Спасибо за исправление, я проверил, смогу ли найти дату. Лично я действительно перешел на использование JOINS только в 2001 или 2 - сначала мне показалось, что это использование немного странно, но сейчас я предпочитаю его.
Не могли бы вы привести пример такой ситуации, когда старый синтаксис обязательно неоднозначен? Спасибо.
Синтаксис JOIN ... ON ... является более поздним дополнением к спецификациям ANSI и ISO для SQL. Синтаксис JOIN ... ON ... обычно предпочтительнее, потому что он 1) перемещает критерии соединения из предложения WHERE, делая предложение WHERE только для фильтрации и 2) делает его более очевидным, если вы создаете ужасный декартово произведение, поскольку каждый JOIN должен сопровождаться как минимум одним предложением ON. Если все критерии соединения просто AND в предложении WHERE, это не так очевидно, когда один или несколько пропущены.
Оператор INNER JOIN можно переписать как CROSS JOIN с предложением WHERE, совпадающим с тем же условием, которое вы использовали в предложении ON запроса INNER JOIN.
Учитывая, что у нас есть следующие таблицы post и post_comment:
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 JOIN позволяет связывать строки, принадлежащие разным таблицам. Например, КРЕСТНОЕ СОЕДИНЕНИЕ создаст декартово произведение, содержащее все возможные комбинации строк между двумя соединяемыми таблицами.
Хотя CROSS JOIN полезен в определенных сценариях, в большинстве случаев вы хотите объединить таблицы на основе определенного условия. И вот здесь в игру вступает INNER JOIN.
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
С другой стороны, если условие предложения 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
Наиболее распространенное условие предложения 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.
Ограничения не имеют отношения к определению соединения, поэтому упоминание их до тех пор, пока не будет объяснено, как работает соединение, вводит в заблуждение.
Я не думаю, что это вводит в заблуждение.
Некоторые ошибки в синтаксисе ANSI JOIN не являются тем, что я бы назвал «ранними». На предыдущей работе, когда мы выполняли много огромных запросов, мы столкнулись с жестким ограничением на количество общих столбцов, которые вы могли бы иметь в запросе, если бы вы использовали синтаксис ANSI JOIN. Вы обнаружите, что, по крайней мере, до выпуска 10g все еще были проблемы.