一条SQL的真正执行顺序

20 阅读1分钟

最近重新过了一下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专门用来过滤分组后的行。