SQL中WHERE与HAVING筛选聚合结果的差异及疑问
WHERE与HAVING子句的筛选差异解析
我需要按每个客户(id)和订单日期的组合,找出金额在50美元至200美元范围内的最大订单金额。但使用分别带WHERE和HAVING子句的两个SQL查询后,得到的结果不同,且预期结果为HAVING子句查询的结果,希望理清两者的筛选差异及原因。
查询1(WHERE子句)
SELECT id, order_date, MAX(price) FROM orders WHERE price BETWEEN 50 AND 200 GROUP BY id;
查询1结果
id order_date MAX(price) 1 2013-01-10 103.50 5 2013-01-01 195.50 6 2013-01-01 172.50 8 2013-01-01 147.20 9 2013-01-01 165.60 10 2013-01-01 184.00 12 2013-01-18 191.40 24 2013-01-02 138.00 25 2013-01-07 100.63 26 2013-01-16 86.71 30 2013-01-03 155.25 35 2013-01-08 96.60 36 2013-01-02 169.74 40 2013-01-03 197.80 45 2013-01-02 124.20 48 2013-01-02 149.04 50 2013-01-03 157.55 52 2013-01-03 173.42 60 2013-01-03 186.30 75 2013-01-02 181.13 100 2013-01-04 147.20 125 2013-01-04 184.00
查询2(HAVING子句)
SELECT id, order_date, MAX(price) FROM orders GROUP BY id HAVING MAX(price) BETWEEN 50 AND 200
查询2结果
id order_date MAX(price) 25 2013-01-03 100.63 26 2013-01-16 86.71 35 2013-01-08 96.60 45 2013-01-02 124.20 52 2013-01-03 173.42
核心差异与原因分析
1. 执行时机不同
- WHERE子句:在分组(GROUP BY)前执行。它先过滤掉所有
price不在50-200范围内的行,再对剩余行按id分组计算最大金额。也就是说,只要客户有至少一笔订单金额符合50-200的条件,就会进入结果(比如id=1的客户,即便有超过200的订单,只要存在符合条件的订单,就会被保留并计算该范围内的最大金额)。 - HAVING子句:在分组后执行。它先对所有订单按
id分组,计算每个客户的所有订单中的最大金额,再过滤掉最大金额不在50-200范围内的分组。只有那些客户的所有订单里,最大金额本身就在50-200区间的分组才会被保留。
2. 筛选对象不同
- WHERE针对单个行的
price值进行筛选,只要某行数据符合条件就会进入后续分组流程。 - HAVING针对分组后的聚合结果(这里是
MAX(price))进行筛选,只有整个分组的聚合值满足条件,该分组才会出现在最终结果中。
3. 额外注意:GROUP BY与SELECT列的不匹配
两个查询中SELECT包含order_date,但GROUP BY仅按id分组,这种写法不符合SQL标准(仅部分数据库如MySQL的非严格模式允许),返回的order_date是该id对应的任意一条订单日期,结果不可靠。如果你的需求是按id和订单日期的组合分组,正确的写法应该是GROUP BY id, order_date。
内容的提问来源于stack exchange,提问作者Lilly_Co
相关产品推荐
相关产品推荐

