WHERE 后跟 ON 子句

Posted

技术标签:

【中文标题】WHERE 后跟 ON 子句【英文标题】:WHERE followed by ON clause 【发布时间】:2021-05-30 14:34:54 【问题描述】:

以下查询之间的语义差异是什么?对我来说,在我快速执行它们之前,它们看起来都很相似。这是 presto 特有的东西还是我在 SQL 标准中遗漏了什么?

形式一: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;

形式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 没有,但它们不应该是等价的吗?

【问题讨论】:

【参考方案1】:

有两个重要的区别。

首先是条件t1.colE = 1LEFT JOIN 将所有行保留在第一个表中,而不管 ON 子句的计算结果如何。因此,t1.colE 不会更改结果集中的行数。但是,它确实具有奇怪的效果,即当此条件不成立时,来自t2 的任何列都是NULL

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

【讨论】:

【参考方案2】:

当您有一个引用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 的行

【讨论】:

【参考方案3】:

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

WHERE 子句确定在查询中应考虑FROM 子句生成的哪些行,因此它的作用是在行被GROUP BYWINDOW 或@ 处理之前对其进行过滤987654327@ 子句。 ON 子句确定是否应考虑将JOIN 左侧和右侧的一对行用于连接操作。 对于 INNER JOIN,如果 ON 子句的计算结果为 false,则行不会相互连接,也不会发出任何结果。 对于LEFT JOIN,如果对于左侧的给定行,ON 子句对于右侧的所有行的评估结果为 false,行包含左侧的值和 NULL 的列右侧发射。相同的逻辑适用于 RIGHT JOIN,但两边颠倒了。 FULL JOINLEFTRIGHT 的组合。

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

【讨论】:

以上是关于WHERE 后跟 ON 子句的主要内容,如果未能解决你的问题,请参考以下文章

在oracle中where 子句和having子句中的区别

使用 JOIN 时的 WHERE 子句与 ON

SQL:在 Where 子句之后加入

MSSQL - 在 where 和 on 子句性能上添加条件

在oracle中where 子句和having子句中的区别

`INNER JOIN` 过滤条件在查询中的位置; `ON` 或 `WHERE` 子句 [关闭]