В чем разница между перекрестным соединением и запятой между двумя таблицами? - PullRequest
35 голосов
/ 13 октября 2010

В чем разница между

select * from A, B

и

select * from A cross join B

?Кажется, они дают одинаковые результаты.

Предпочитается ли вторая версия первой?Первая версия полностью синтаксически неверна?

Ответы [ 8 ]

34 голосов
/ 13 октября 2010

Они возвращают одинаковые результаты, поскольку они семантически идентичны.Это:

select * 
  from A, B

... - это (wince) синтаксис ANSI-89.Без предложения WHERE, связывающего таблицы вместе, результатом является декартово произведение.Именно это и обеспечивает альтернатива:

    select * 
      from A 
cross join B

... но CROSS JOIN - это синтаксис ANSI-92.

О производительности

Разницы в производительности междуих.

Зачем использовать ANSI-92?

Причина использования синтаксиса ANSI-92 - для поддержки OUTER JOIN (IE: LEFT, FULL, RIGHT) - синтаксис ANSI-89 не имеетлюбая, так много баз данных реализовали свои собственные (которые не портируются ни на какие другие базы данных).IE: Oracle (+), SQL Server =*

7 голосов
/ 16 июля 2015

Наткнулся на этот пост из другого SO вопроса, но большая разница заключается в создании перекрестного соединения. Например, при использовании cross apply или другого объединения после B в первом (запятом) варианте перекрестное применение или объединение будут ссылаться только на таблицы (таблицы) после точки. например, следующее:

select * from A, B join C on C.SomeField = A.SomeField and C.SomeField = B.SomeField 

создаст ошибку:

Не удалось связать многоэлементный идентификатор "A.SomeField".

потому что объединение на C распространяется только на B, тогда как то же самое с перекрестным соединением ...

select * from A cross join B join C on C.SomeField = A.SomeField and C.SomeField = B.SomeField 

.. считается нормальным. То же самое применимо, если используется cross apply. Например, поместив крестик на функцию после B, функция может использовать только поля B, где один и тот же запрос с перекрестным объединением может использовать поля как A, так и B. Конечно, это также означает, что может быть использовано и обратное. Если вы хотите добавить объединение исключительно для одной из таблиц, этого можно добиться, введя «запятую» в таблицах.

6 голосов
/ 13 октября 2010

Они одинаковы и никогда не должны использоваться (почти).

3 голосов
/ 13 октября 2010

Первая версия изначально была единственным способом объединения двух таблиц. Но у него есть ряд проблем, поэтому ключевое слово JOIN было добавлено в стандарт ANSI-92. Они дают те же результаты, но второй является более явным и предпочтительным.

1 голос
/ 13 октября 2010

Это примеры неявных и явных перекрестных объединений. Смотри http://en.wikipedia.org/wiki/Join_%28SQL%29#Cross_join.

0 голосов
/ 18 февраля 2019

Помимо краткости (в пользу ,) и последовательности (в пользу CROSS JOIN), единственным отличием является приоритет.

Запятая имеет более низкий приоритет, чем другие объединения.


Например, явная форма

SELECT *
FROM a
  CROSS JOIN b
  JOIN c ON a.id = c.id

есть

SELECT *
FROM (
  a
  CROSS JOIN b
)
  INNER JOIN c ON a.id = c.id

, который действителен.

В то время как явная форма

SELECT *
FROM a,
  b
  JOIN c ON a.id = c.id

есть

SELECT *
FROM a
  CROSS JOIN (
    b
    INNER JOIN c ON a.id = c.id
  )

, что недопустимо (предложение объединения ссылается на недоступность a).


В вашем примере есть только две таблицы, поэтому два запроса в точности эквивалентны.

0 голосов
/ 10 октября 2016

Добавить к ответам уже дано:

select * from A, B

Это был единственный способ присоединения до стандарта SQL 1992 года. Поэтому, если вы хотите внутреннее объединение, вы должны будете использовать условие WHERE для критериев:

select * from A, B
where A.x = B.y;

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

select * from A, B, C, D
where B.id = C.id_b
and C.id_d = D.id;

Здесь мы имеем перекрестное соединение A с B / C / D. Нарочно или нет? Может быть, программист просто забыл and B.id = A.id_b (или что-то в этом роде), или, возможно, эта строка была удалена по ошибке, и, возможно, все-таки это действительно было перекрестное соединение. Кто мог сказать?

Здесь то же самое с явными объединениями

select * 
from A
cross join B
inner join C on C.id_b = B.id
inner join D on D.id = C.id_d;

Больше нет сомнений в намерениях программистов.

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

0 голосов
/ 03 июня 2014

Что касается комментариев относительно полезности перекрестных объединений, то есть один очень полезный и правильный пример использования перекрестных объединений или запятых в общепризнанно немного неясном мире Postgres generate_series и Postgis пространственного sql, где вы можете использовать перекрестное объединение против generate_series чтобы извлечь n-ю геометрию из коллекции геометрии или Multi- (Polygon / Point / Linestring), см .: http://postgis.refractions.net/documentation/manual-1.4/ST_GeometryN.html

SELECT n, ST_AsEWKT(ST_GeometryN(the_geom, n)) As geomewkt
  FROM (
    VALUES (ST_GeomFromEWKT('MULTIPOINT(1 2 7, 3 4 7, 5 6 7, 8 9 10)') ),
          ( ST_GeomFromEWKT('MULTICURVE(CIRCULARSTRING(2.5 2.5,4.5 2.5, 3.5 3.5), (10 11, 12 11))') )
    )  As foo(the_geom)
CROSS JOIN generate_series(1,100) n
  WHERE n <= ST_NumGeometries(the_geom);

Это может быть очень полезно, если вы хотите получить область, центроид, ограничивающий прямоугольник или многие другие операции, которые вы можете выполнять с одной геометрией, если они содержатся внутри более крупной.

Я всегда писал такие запросы, используя запятую перед generate_series, пока однажды я не задумался, действительно ли это означает перекрестное соединение, что привело меня к этому посту. Неясный, но определенно полезный.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...