【问题标题】: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 中取消嵌套数组和结构是个好主意

标签: sql sql-server database tsql select


【解决方案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”开头:)
        • 虽然这是一个旧帖子,但纯粹是为了记录:使用另一个连接或交叉应用时会有所不同(stackoverflow.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 语法使用逗号。
          猜你喜欢
          • 2017-02-08
          • 2011-02-12
          • 1970-01-01
          • 2020-03-24
          • 1970-01-01
          • 2023-03-08
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多