WHERE 后跟 ON 子句

WHERE followed by ON clause

以下查询之间的语义区别是什么?对我来说,两者看起来很相似,直到我立即执行它们。这是 presto 特有的东西还是我在 SQL 标准中遗漏了什么?

形式 1:ON 子句中指定的所有条件。

SELECT
    t1.colA,
    t1.colB,
    t1.colC,
    t2.colD
FROM t1
LEFT OUTER JOIN t2
    ON t1.colA = t2.colA
    AND t1.colB = t2.colB
    AND t1.colE = 1
    AND t2.colF = 2;

形式二:部分条件在WHERE子句中指定。

SELECT
    t1.colA,
    t1.colB,
    t1.colC,
    t2.colD
FROM t1
LEFT OUTER JOIN t2
    ON t1.colA = t2.colA
    AND t1.colB = t2.colB
WHERE
    t1.colE = 1
    AND t2.colF = 2;

表格 1 会产生一些行,但表格 2 不会,但它们不应该是等价的吗?

有两个重要区别。

首先是条件t1.colE = 1LEFT JOIN 保留第一个 table 中的所有行,而不管 ON 子句的计算结果。因此,t1.colE 不会更改结果集中的行数。然而,当这个条件不成立时,t2 中的任何列都是 NULL.

第二个条件t2.colF = 2有不同的效果。这会将 LEFT JOIN 变成 INNER JOIN,因为 NULL 值与 WHERE 子句不匹配。

当您有引用 right_tableLEFT [OUTER] JOINWHERE 子句时,它等同于 [INNER] JOIN。即下面两个是等价的:

-- [inner] join
select ...
from left_table
join right_table 
  on left_table.cola = right_table.cola 
 and right_table.colb = 2

-- left [outer] join + where
select ...
from left_table
left join right_table
       on left_table.cola = right_table.cola
where right_table.colb = 2

您的第二个示例查询在 where 子句中有一个 left join 和这个条件 t2.colF = 2,使其与第一个查询不同。

其中第一个包括来自 t1 的所有行,第二个仅包括 t1.colE = 1t2.colF = 2

的行

思考WHERE子句和ON子句区别的方法是:

  • WHERE 子句确定查询中应考虑由 FROM 子句生成的哪些行,因此它的作用是在行被 [=14= 处理之前对其进行过滤]、WINDOWSELECT 子句。
  • ON 子句确定是否应考虑将 JOIN 左右两侧的一对行用于连接操作。
    • 对于 INNER JOIN,如果 ON 子句的计算结果为 false,则行不会相互连接并且不会发出任何结果。
    • 对于 LEFT JOIN,如果对于左侧的给定行,ON 子句对右侧所有行的计算结果为 false,则包含左侧值的行并发出右侧列的 NULL。同样的逻辑适用于 RIGHT JOIN,但两侧相反。
    • FULL JOINLEFTRIGHT 联接的组合。

在您的示例中,第二个查询,由于 ON 子句评估为 false,由 LEFT JOIN 生成的任何行在右侧的列中包含 NULL 将是由 t2.colF = 2 表达式 WHERE 子句过滤掉。