SQL ANSI JOIN 优先级

孔夫子*_*孔夫子 8 mysql postgresql oracle join sql-server

我有一个看起来像这样的查询:

    SELECT *
      FROM TBLA A
 LEFT JOIN TBLB B ON A.Col1 = B.Col2
RIGHT JOIN TBLC C ON B.Col3 = C.Col4
      JOIN TBLD D ON C.Col5 = D.Col6
Run Code Online (Sandbox Code Playgroud)

将按照什么顺序解析连接?我对 SQL Server 最感兴趣,并将对它的解释标记为答案,但我对 ANSI/ISO 标准及其在各种 RDBMS 中的工作方式同样感兴趣。

这个问题的原因是为了弄清楚为什么结果与这个查询不同

    SELECT *
      FROM TBLA A
CROSS JOIN TBLC C
 LEFT JOIN TBLB B ON A.Col1 = B.Col2 AND B.Col3 = C.Col4
      JOIN TBLD D ON C.Col5 = D.Col6
Run Code Online (Sandbox Code Playgroud)

Mar*_*ith 8

从逻辑上讲,连接是按照ON从左到右的子句顺序解析的。

每个连接的输出是进入下一个连接的虚拟表。

因此,对于您问题中的查询,A LJ B然后将 的虚拟表结果正确连接到C. 的连接条件B.Col3 = C.Col4将丢失原始左连接保留的任何空扩展行,有效地将第一个连接转换回内部连接,然后生成的虚拟表(保留来自 的所有行C)被内部连接到 上D

所以你的初始查询可以简化为

SELECT *
FROM TBLA A
INNER JOIN TBLB B ON A.Col1 = B.Col2
RIGHT JOIN TBLC C ON B.Col3 = C.Col4
      JOIN TBLD D ON C.Col5 = D.Col6
Run Code Online (Sandbox Code Playgroud)

这实际上与 (A IJ B) ROJ (C IJ D)

ON子句的顺序不一定与表在查询中出现的顺序相同。这也可以改写为(C IJ D) LOJ (A IJ B)

SELECT *
FROM   TBLC C
       INNER JOIN TBLD D
         ON C.Col5 = D.Col6
       LEFT JOIN TBLA A
                 INNER JOIN TBLB B
                   ON A.Col1 = B.Col2
         ON B.Col3 = C.Col4 
Run Code Online (Sandbox Code Playgroud)

on 子句的位置意味着外连接是在两个虚拟表之间执行的 (C IJ D)(A IJ B)而不仅仅是单个表。

在您的第二个查询概念上,虚拟表A x C左连接到 B 保留整个笛卡尔积,然后将结果D与谓词连接C.Col5 = D.Col6。不内在这消除了从最终结果没有任何行会合之间CD这意味着它等同于

SELECT *
FROM   TBLC C
       JOIN TBLD D
         ON C.Col5 = D.Col6
       CROSS JOIN TBLA A
       LEFT JOIN TBLB B
         ON A.Col1 = B.Col2
            AND B.Col3 = C.Col4 
Run Code Online (Sandbox Code Playgroud)