В чем разница между
select * from A, B
и
select * from A cross join B
? Кажется, что они возвращают те же результаты.
Является ли вторая версия предпочтительной для первой? Является ли первая версия полностью синтаксически неправильной?
В чем разница между
select * from A, B
и
select * from A cross join B
? Кажется, что они возвращают те же результаты.
Является ли вторая версия предпочтительной для первой? Является ли первая версия полностью синтаксически неправильной?
Они возвращают те же результаты, потому что они семантически идентичны. Это:
select *
from A, B
... (синтаксис) ANSI-89. Без предложения WHERE, чтобы связать таблицы вместе, результатом является декартово произведение. Именно это и обеспечивает альтернатива:
select *
from A
cross join B
... но CROSS JOIN - синтаксис ANSI-92.
Там нет разницы в производительности.
Причиной использования синтаксиса ANSI-92 является поддержка OUTER JOIN (IE: LEFT, FULL, RIGHT). Синтаксис ANSI-89 не имеет, поэтому многие базы данных реализовали свои собственные (которые не переносят на любые другие базы данных). IE: Oracle (+)
, SQL Server =*
Они одинаковы и должны (почти) никогда не использоваться.
Наткнулся на этот пост из другого вопроса 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.
Конечно, это также означает, что можно использовать обратное. Если вы хотите добавить соединение только для одной из таблиц, вы можете добиться этого, перейдя в "запятую" в таблицах.
Первая версия изначально была единственным способом объединения двух таблиц. Но у него есть ряд проблем, поэтому ключевое слово JOIN было добавлено в стандарте ANSI-92. Они дают те же результаты, но второй более явный и должен быть предпочтительным.
Это примеры неявных и явных кросс-объединений. См. http://en.wikipedia.org/wiki/Join_%28SQL%29#Cross_join.
К комментариям относительно полезности кросс-объединений есть один очень полезный и обоснованный пример использования кросс-соединений или запятых в, по общему признанию, несколько неясном мире 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, до тех пор, пока я не задался вопросом, действительно ли это означало перекрестное соединение, которое привело меня к этому сообщению. Неясно, но определенно полезно.
Чтобы добавить к уже полученным ответам:
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;
Нет сомнений в намерениях программистов.
Старый синтаксис, разделенный запятыми, был заменен по уважительным причинам и больше не должен использоваться.