在SQL中,JOIN和CROSS JOIN有什么区别?

10

这两者之间有什么区别:

select t1.a1, t1.a2, t1.a3 from t1 cross join t2 where t1.a3 = t2.a1

并且:

select t1.a1, t1.a2, t1.a3 from t1,t2 where t1.a3=t2.a1;

我能够交替使用它们吗?

3个回答

15

SQL有以下几种连接类型,全部来自于集合论:

  • 内连接。
    From A inner join B等同于A ∩ B,提供两个集合都共有的元素集合。

  • 左连接。
    From A left outer join B等同于(A − B) ∪ (A ∩ B)。每个A至少会出现一次;如果有多个匹配的B,则每个匹配的B都会重复一次。

  • 右连接。
    From A right outer join B等同于(A ∩ B) ∪ (B − A)。它与表交换位置的左连接完全相同。每个B至少会出现一次;如果有多个匹配的A,每个匹配的B都会重复一次。

  • 全连接。
    From A full outer join B等同于(A − B) ∪ (A ∩ B) ∪ (B − A)。每个A和每个B都至少会出现一次。如果一个A匹配多个B,则每个匹配的A都会重复一次;如果一个B匹配多个A,则每个匹配的B都会重复一次。

  • 交叉连接。
    From A cross join B产生A × B的笛卡尔积。每个A将为每个B重复一次。如果A有100行,B也有100行,则结果集将包含10,000行。

应该注意到,select查询的理论执行包括按照以下顺序执行的步骤:

  1. 计算from子句中源集合的完全笛卡尔积以启动候选结果集。

  • 根据from子句中的连接条件,缩小候选结果集。

  • 根据where子句中的条件,进一步缩小候选结果集。

  • 根据group by子句中的条件,将候选结果集分成组。

  • 从候选结果集中删除除与group by子句相关或与聚合函数评估相关的列之外的任何列。

  • 为候选结果集中的每个组计算任何此类聚合函数的值。

  • 将候选结果集中的每个组折叠成一个单行,其中包括分组列和计算出的每个聚合函数的值。现在,候选结果集每个组对应一行,除了group by列或该组的聚合函数的计算值之外,所有列都被消除。

  • 根据having子句中的条件缩小候选结果集并生成最终结果集。

  • 按照order by子句中的条件对最终结果集进行排序并输出结果。

  • 还有更多步骤与computecompute by子句有关,但这已足以了解其工作原理。

    还应注意的是,除了最简单的实现方式外,没有什么会真正按照这种方式评估select语句,但产生的结果必须与完全执行上述步骤时产生的结果相同。


    7

    MySQL没有区分JOINCROSS JOIN。它们是相同的。

    在你的两个示例中,这个子句

    WHERE t1.a3 = t2.a1 
    

    将任何类型的连接转换为内部连接。 表达此查询的标准方法是:
    SELECT t1.a1, t1.a2, t1.a3 
      FROM t1 
      JOIN t2 ON t1.a3 = t2.a1
    

    1
    强调:正确的方式 - 也是唯一的“正确”方式来表达查询 - 是使用显式的join语法。其他方法是允许的,但它们不具备外连接的灵活性。 - Gordon Linoff

    3

    没有区别,尽管可以对此微笑。首先进行交叉连接,然后使用where语句将其转换为内部连接(至少在第一个join中)。这种写法超过20年了,在复杂语句中容易出现错误。我建议使用新的花式写法,像这样:

    select t1.a1, t1.a2, t1.a3 
    from t1 
    inner join t2 on t1.a3 = t2.a1
    

    我没有MySQL可用来测试这个,但我很好奇第一个示例和第二个示例之间的执行计划是否有任何不同。你知道优化器如何处理这两个吗? - Dan
    1
    我刚刚尝试了一下,优化器将它们转换为完全相同的查询。 - fancyPants

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接