You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

不含聚合函数的HAVING条件是否始终与WHERE完全等价?

HAVING与WHERE引用GROUP BY键列时是否始终等价?

我在PostgreSQL测试套件里看到一段有意思的注释,对应的SQL代码如下:

-- HAVING is effectively equivalent to WHERE in this case
SELECT b, c FROM test_having
    GROUP BY b, c HAVING b = 3 ORDER BY b, c;

这让我产生疑问:当HAVING子句引用GROUP BY键列(非聚合值)时,是否在功能上完全等价于WHERE?有没有例外情况?


多数场景下两者等价

当HAVING仅过滤GROUP BY的键列时,通常和WHERE的效果一致。因为GROUP BY键列在每个分组中是唯一的——每个分组对应一组键列值,HAVING过滤这些分组,和先用WHERE过滤原始行(只保留符合键列条件的行)再分组,最终得到的分组集合完全相同。

存在等价性不成立的场景

1. 使用ROLLUP/CUBE/GROUPING SETS等扩展分组语法

这类语法会生成汇总分组行(比如ROLLUP会生成包含NULL的汇总行,代表更高层级的聚合)。此时HAVING过滤的是所有分组(包括汇总行),而WHERE是先过滤原始行再分组,两者结果会明显不同。

举个例子:
假设test_having表数据如下:

bc
31
32
45

用WHERE的情况:

SELECT b, SUM(c) FROM test_having 
WHERE b = 3 
GROUP BY ROLLUP(b);

结果会包含b=3的分组和对应的汇总行:

bsum
33
NULL3

用HAVING的情况:

SELECT b, SUM(c) FROM test_having 
GROUP BY ROLLUP(b) 
HAVING b = 3;

结果只会保留b=3的分组,过滤掉了b为NULL的汇总行:

bsum
33

2. 结合GROUPING()函数判断分组类型

当使用GROUPING()函数区分普通分组和汇总分组时,HAVING可以基于这个函数过滤,而WHERE无法做到(因为GROUPING()是分组后计算的)。比如:

SELECT b, SUM(c), GROUPING(b) AS is_total
FROM test_having 
GROUP BY ROLLUP(b) 
HAVING GROUPING(b) = 0 AND b =3;

这个HAVING既过滤了普通分组(排除汇总行)又限定b=3,而WHERE只能先过滤b=3,无法区分分组类型;如果逻辑是HAVING GROUPING(b)=1(只保留汇总行),WHERE完全无法实现等价效果。


总结

仅在简单GROUP BY(无扩展分组语法)、HAVING仅过滤GROUP BY键列的场景下,两者等价。一旦涉及扩展分组生成的汇总行,或者结合分组相关的函数(如GROUPING()),HAVING和WHERE的功能就会出现差异。

内容的提问来源于stack exchange,提问作者Mason Wheeler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 10:56:10