使用交叉连接和在两个表之间放置逗号有啥区别?
Posted
技术标签:
【中文标题】使用交叉连接和在两个表之间放置逗号有啥区别?【英文标题】:What is the difference between using a cross join and putting a comma between the two tables?使用交叉连接和在两个表之间放置逗号有什么区别? 【发布时间】:2011-04-24 12:45:15 【问题描述】:有什么区别
select * from A, B
和
select * from A cross join B
?它们似乎返回相同的结果。
第二个版本比第一个更受欢迎吗?第一个版本在语法上完全错误吗?
【问题讨论】:
笛卡尔积几乎从来没有用过...... 但在极少数情况下,很高兴知道编写它们的正确方法。 很少有用,但可能在每个主要项目中至少存在一次。 交叉连接实际上有很多用途,例如生成样本数据或在地理信息处理 (PostGIS) 中。我经常使用它,例如计算一个点与其他点交叉连接的距离(ST_Distance)... 在 BigQuery 中取消嵌套数组和结构是个好主意 【参考方案1】:除了简洁(喜欢,
)和一致性(喜欢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
)。
在您的示例中,只有两个表,因此两个查询完全相同。
【讨论】:
【参考方案2】:添加到已经给出的答案:
select * from A, B
这是在 1992 年 SQL 标准之前加入的唯一方法。因此,如果您想要内部连接,则必须使用 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;
不再怀疑程序员的意图了。
旧的逗号分隔语法已被替换,不应再使用。
【讨论】:
【参考方案3】:从另一个 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的字段。
当然,这也意味着反过来也可以使用。如果您只想为其中一个表添加连接,可以通过在表上添加“逗号”来实现。
【讨论】:
几分钟前发现了同样的东西...很高兴在这里添加这个!【参考方案4】:对于交叉连接的实用性的 cmets,在公认有点晦涩的 Postgres generate_series 和 Postgis 空间 sql 世界中,有一个使用交叉连接或逗号的非常有用且有效的示例,您可以在其中对 generate_series 使用交叉连接要从几何集合或多(多边形/点/线串)中提取第 n 个几何,请参阅: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 之前使用逗号来编写这样的查询,直到有一天我想知道这是否真的意味着交叉连接,这让我写了这篇文章。晦涩难懂,但绝对有用。
【讨论】:
【参考方案5】:它们返回相同的结果,因为它们在语义上是相同的。这个:
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 的=*
【讨论】:
+1,但 FWIW 它们在语法上并不相同——它们在语义上相同。 @Bill Karwin:呸!都以“s”开头:) 虽然这是一个旧帖子,但纯粹是为了记录:使用另一个连接或交叉应用时会有所不同(***.com/a/31441463/1431042)【参考方案6】:这些是隐式和显式交叉连接的示例。见http://en.wikipedia.org/wiki/Join_%28SQL%29#Cross_join。
【讨论】:
我不同意它们是显式/隐式的——两者都是 ANSI 标准,并且 ANSI-89 格式被认为已弃用。【参考方案7】:第一个版本最初是连接两个表的唯一方法。但它有许多问题,因此在 ANSI-92 标准中添加了 JOIN 关键字。它们给出了相同的结果,但第二个更明确并且是首选。
【讨论】:
【参考方案8】:它们是相同的,应该(几乎)永远不要使用。
【讨论】:
但是如果你确实需要交叉加入它们,请使用后者:-)交叉加入得到那个快捷符号是很愚蠢的。 我认为“快捷表示法”早于交叉连接表示法。 你说得对——CROSS JOIN
在 SQL:1992 中成为 ANSI 标准,而 ANSI SQL:1989 语法使用逗号。以上是关于使用交叉连接和在两个表之间放置逗号有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章