最近重新过了一下sql基础,做题的时候发现明明SELECT已经算出了avg_score,为什么 WHERE 却用不了?
SELECT s.classid, s.sid, s.sname, AVG(r.score) AS avg_score
FROM student s
JOIN result r ON s.sid = r.sid
WHERE avg_score < 80 -- ❌ 这里为什么不行?
GROUP BY s.sid;
这是因为SQL的执行顺序不是按照写的顺序执行的!
SQL的实际执行顺序是:
- 先执行from,join来确定表之间的连接关系,得到初步的数据
- where对数据进行普通的初步的筛选
- group by 分组
- 各组分别执行having中的普通筛选或者聚合函数筛选。
- 然后把再根据我们要的数据进行select,可以是普通字段查询也可以是获取聚合函数的查询结果,如果是集合函数,select的查询结果会新增一条字段
- 将查询结果去重distinct
- 最后合并各组的查询结果,按照order by的条件进行排序
所以正确的sql应该使用having对聚合后的结果进行筛选:
SELECT s.classid, s.sid, s.sname, AVG(r.score) AS avg_score
FROM student AS s
INNER JOIN result r ON s.sid = r.sid
GROUP BY s.sid
HAVING avg_score < 80;
-
WHERE执行时:- 还没有分组
- 也还没有 avg_score
-
HAVING执行时:- 分组已经完成
- 聚合结果已经算出来
结论:WHERE用来过滤原始行,HAVING专门用来过滤分组后的行。