使用交叉连接和在两个表之间放置逗号有啥区别?

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 applyB 之后的另一个连接,交叉应用或连接将仅引用点后面的表。例如,以下内容:

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 语法使用逗号。

以上是关于使用交叉连接和在两个表之间放置逗号有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

用逗号分隔表的查询是交叉连接查询吗?

“,”和“;”有啥区别?

如何在 *ngFor 中的数组元素之间放置逗号?

请问VB中PRINT语句后面用分号和逗号有啥区别?

使用C在csv中的逗号之间放置零

在 ORACLE 中,有没有办法使用两个表将多行行连接成一个行,其中最终值用逗号分隔?