实用指南:SQL执行顺序
SQL语句的执行顺序并非严格按照书写顺序,而是遵循一套逻辑流程。理解这一顺序是编写高效查询和排查问题的关键。以下是完整执行阶段的详细解析,结合你的查询案例进行说明:
一、SQL执行顺序全阶段(按实际执行先后排序)
| 阶段序号 | 关键字/操作 | 作用说明 |
|---|---|---|
| 1 | FROM | 从指定表中读取原始数据,作为整个查询的数据源 |
| 2 | JOIN + ON | 关联其他表,根据ON条件合并数据(如LEFT JOIN保留左表所有记录) |
| 3 | WHERE | 过滤行数据,仅保留满足条件的记录(不能使用聚合函数) |
| 4 | GROUP BY | 将结果集按指定列分组,每组数据作为独立单元后续处理 |
| 5 | HAVING | 过滤分组数据,仅保留满足条件的分组(可使用聚合函数,如HAVING COUNT(*) > 10) |
| 6 | SELECT | 选择需要返回的列(包括计算列和别名),此时才会解析AS定义的别名 |
| 7 | DISTINCT | 对SELECT结果去重(若使用) |
| 8 | ORDER BY | 对最终结果按指定列排序(可使用SELECT中定义的别名) |
| 9 | LIMIT | 限制返回的行数(如分页查询) |
二、结合你的查询案例拆解执行步骤
SELECT
Signups.user_id,
ROUND(IFNULL(AVG(Confirmations.action = 'confirmed'), 0), 2) AS confirmation_rate
FROM Signups
LEFT JOIN Confirmations ON Signups.user_id = Confirmations.user_id
-- WHERE (此处无该子句)
GROUP BY Signups.user_id
-- HAVING (此处无该子句)
-- ORDER BY (此处无该子句)
1. FROM Signups
- 操作:从
Signups表读取所有用户的基础信息(如user_id)。 - 输出:
[ {user_id: 1}, {user_id: 2}, ... ](仅含Signups表数据)。
2. LEFT JOIN Confirmations ON ...
- 操作:根据
user_id关联Confirmations表,保留Signups表所有用户,即使该用户无确认记录。 - 输出:
[ {user_id: 1, action: 'confirmed'}, // 有确认记录 {user_id: 1, action: 'ignored'}, // 有确认记录 {user_id: 2, action: NULL} // 无确认记录(左连接补NULL) ]
3. GROUP BY Signups.user_id
- 操作:按
user_id将数据分组,每个用户成为独立组。 - 输出:
组1(user_id=1): [ {action: 'confirmed'}, {action: 'ignored'} ] 组2(user_id=2): [ {action: NULL} ]
4. SELECT 与聚合计算
- 操作:对每个组执行
AVG(Confirmations.action = 'confirmed'):- 组1:
(1 + 0) / 2 = 0.5→ROUND(0.5, 2) = 0.50 - 组2:
IFNULL(AVG(NULL), 0) = 0→ROUND(0, 2) = 0.00
- 组1:
- 输出最终结果:
+---------+-------------------+ | user_id | confirmation_rate | +---------+-------------------+ | 1 | 0.50 | | 2 | 0.00 | +---------+-------------------+
三、关键注意事项
WHEREvsHAVINGWHERE在分组前过滤行,不能使用聚合函数(如WHERE AVG(...) > 0.5是错误的)。HAVING在分组后过滤组,可使用聚合函数(如HAVING confirmation_rate > 0.5)。
别名的可见性
SELECT中定义的别名(如confirmation_rate)只能在ORDER BY和HAVING中使用,不能在WHERE或GROUP BY中使用(因为执行顺序靠后)。
SELECT的执行时机SELECT是倒数第4个执行的阶段,因此在书写复杂查询时,需注意早期阶段(如WHERE)无法引用SELECT中定义的计算列。
四、执行顺序与书写顺序对比
| 书写顺序(从上到下) | 实际执行顺序(从1到9) |
|---|---|
| SELECT | 6 |
| FROM | 1 |
| JOIN | 2 |
| WHERE | 3 |
| GROUP BY | 4 |
| HAVING | 5 |
| ORDER BY | 8 |
| LIMIT | 9 |
五、记忆口诀
为方便记忆,可使用以下口诀:
“从(FROM)哪张表来,联(JOIN)哪些数据,过(WHERE)滤掉杂质,分(GROUP BY)成小组看,组内过(HAVING)滤,选(SELECT)出结果,去(DISTINCT)重,排(ORDER BY)个序,取(LIMIT)前几名。”

浙公网安备 33010602011771号