SELECT语句逻辑执行顺序,你知道吗?

本文解析了SQL语句的执行顺序,并通过三个实例说明了不同子句间的执行先后次序对查询结果的影响。了解这些基础知识有助于编写更高效、更准确的SQL查询。


引言


这不是一个什么多深的技术问题,多么牛叉的编程能力。这跟一个人的开发能力也没有非常必然的直接关系,但是知道这些会对你的SQL编写,排忧及优化上会有很大的帮助。它不是一个复杂的知识点,但是一个非常基础的SQL根基。不了解这些,你一直用普通水泥盖房子;掌握这些,你是在用高等水泥盖房子。

然而,就是这么一个小小的知识点,大家可以去调查一下周围的同事朋友,没准你会得到一个“惊喜”。

由于这篇文章是突然有感而写,下面随手编写的SQL语句没有经过测试。

看下面的几段SQL语句:
SELECT ID,COUNT(ID) AS TOTAL
FROM STUDENT
GROUP BY ID
HAVING TOTAL>2

SELECT ID,COUNT(ID) AS TOTAL
FROM STUDENT
GROUP BY ID
ORDER BY TOTAL

SELECT FIRSTNAME+' '+LASTNAME AS NAME, COUNT(*) AS COUNT 
FROM STUDENT
GROUP BY NAME

你觉得哪一个能够成功执行?

言归正传

下面是SELECT语句的逻辑执行顺序:
  1. FROM
  2. ON
  3. JOIN
  4. WHERE
  5. GROUP BY
  6. WITH CUBE or WITH ROLLUP
  7. HAVING
  8. SELECT
  9. DISTINCT
  10. ORDER BY
  11. TOP
MICROSOFT指出,SELECT语句的实际物理执行顺序可能会由于查询处理器的不同而与这个顺序有所出入。

几个示例


示例一

SELECT ID,COUNT(ID) AS TOTAL
FROM STUDENT
GROUP BY ID
HAVING TOTAL>2

觉得这个SQL语句眼熟吗?对,非常基础的分组查询。但它不能执行成功,因为HAVING的执行顺序在SELECT之上。
实际执行顺序如下:
  1. FROM STUDENT
  2. GROUP BY ID
  3. HAVING TOTAL>2
  4. SELECT ID,COUNT(ID) AS TOTAL
很明显,TOTAL是在最后一句SELECT ID,COUNT(ID) AS TOTAL执行过后生成的新别名。因此,在HAVING TOTAL>2执行时是不能识别TOTAL的。

示例二

SELECT ID,COUNT(ID) AS TOTAL
FROM STUDENT
GROUP BY ID
ORDER BY TOTAL

这个的实际执行顺序是:
  1. FROM STUDENT
  2. GROUP BY ID
  3. SELECT ID,COUNT(ID) AS TOTAL
  4. ORDER BY TOTAL
这一次没有任何问题,能够成功执行。如果把ORDER BY TOTAL换成ORDER BY COUNT(ID)呢?

SELECT ID,COUNT(ID) AS TOTAL
FROM STUDENT
GROUP BY ID
ORDER BY COUNT(ID)
实际执行顺序:
  1. FROM STUDENT
  2. GROUP BY ID
  3. SELECT ID,COUNT(ID) AS TOTAL
  4. ORDER BY COUNT(ID)
没错,它是能够成功执行的,看SQL执行计划,它与上面ORDER BY TOTAL是一样的。ORDER BY 是在SELECT后执行,因此可以用别名TOTAL。


示例三

SELECT FIRSTNAME+' '+LASTNAME AS NAME, COUNT(*) AS COUNT 
FROM STUDENT
GROUP BY NAME

实际执行顺序:
FROM STUDENT
GROUP BY NAME
SELECT FIRSTNAME+' '+LASTNAME AS NAME,COUNT(*) AS COUNT

很明显,执行GROUP BY NAME时别名NAME还没有创建,因此它是不能执行成功的。


总结


回忆起曾经随意问过一些人这个问题,不管谁说不知道时我们都会故意嘲笑一翻,当然此嘲笑非彼嘲笑。但事实证明还是有一些人不会注意到这个知识点,在此贴出来只是做为一个友好的提醒。





<think>嗯,用户想了解SQL中SELECT查询语句逻辑执行顺序。从对话历史看,用户已经引用了好几篇资料,内容都聚焦在SQL查询的逻辑执行顺序上。 用户提供的引用材料非常全面:[^1]提出了核心问题,[^2][^3][^4]则详细列出了不同阶段的执行顺序。虽然各家表述略有差异,但核心逻辑是一致的:FROM/JOIN最先执行,WHERE过滤早于GROUP BY分组,而SELECT投影和ORDER BY排序则是靠后的操作。 用户可能是数据库初学者,正在学习SQL执行原理。这类知识对理解查询优化很重要,特别是在编写复杂查询或性能调优时。用户特意强调“逻辑顺序”而非“物理顺序”,说明ta关注的是SQL标准规范而非具体数据库实现。 需要特别注意微软在[^3]中的提醒:物理执行顺序可能因查询处理器优化而不同。这点很重要,应该在回答中明确区分逻辑顺序和物理执行的区别。 准备用三步结构回答:先用流程图展示标准顺序;再分步骤解释各阶段作用;最后强调逻辑顺序与物理执行的差异。用户引用的序号系统很清晰,可以沿用[^2][^^3][^4]的编号方式但需整合差异点。 数据准备阶段要举例说明,比如用员工部门和薪资表,这样用户更容易理解JOIN和GROUP BY的实际效果。LIMIT和TOP在[^2][^4]中位置不同,需说明这是数据库方言差异。 相关问题设计要递进:从原理验证到实际错误排查,再到性能优化,覆盖用户可能的学习路径。特别是索引使用和子查询位置的问题,这往往是初学者容易困惑的点。 </think>以下是典型的SQL `SELECT` 查询语句的**逻辑执行顺序**(非物理执行顺序),综合参考各权威资料[^2][^3][^4]: ```mermaid graph TD A[FROM 表] --> B[ON 连接条件] B --> C[JOIN 关联表] C --> D[WHERE 行级过滤] D --> E[GROUP BY 分组] E --> F[WITH CUBE/ROLLUP 多维聚合] F --> G[HAVING 组级过滤] G --> H[SELECT 投影列] H --> I[DISTINCT 去重] I --> J[ORDER BY 排序] J --> K[TOP/LIMIT 限制行数] ``` ### 分步详解: 1. **`FROM` & `JOIN`** 先定位数据源表,再通过`ON`条件执行关联(如左表`employees`关联右表`departments`)[^2][^4]。 *示例:* ```sql FROM employees e JOIN departments d ON e.dept_id = d.id ``` 2. **`WHERE`** 对**关联后的结果集**逐行过滤(如筛掉薪资小于5000的记录)[^3][^4]。 *注意:不可在此使用聚合函数(如`SUM(salary)`)*。 3. **`GROUP BY`** 按指定列分组(如按部门分组统计)[^2][^4]。 ```sql GROUP BY d.dept_name ``` 4. **`HAVING`** 对**分组后的结果**过滤(如保留总薪资>10万的组)[^4]。 *与`WHERE`区别:可在此使用聚合函数*。 ```sql HAVING SUM(e.salary) > 100000 ``` 5. **`SELECT`** 选择最终输出的列(此时才计算列表达式/别名)[^3][^4]。 ```sql SELECT d.dept_name, SUM(e.salary) AS total_salary ``` 6. **`DISTINCT`** 对`SELECT`结果去重(如删除重复部门名)[^2][^4]。 7. **`ORDER BY`** 按列排序结果(如按总薪资降序)[^3]。 *注意:此处可使用`SELECT`中的别名(如`total_salary`)。* 8. **`TOP`/`LIMIT`** 限制返回行数(如取前3名)[^2][^4]。 --- ### 关键结论: - **逻辑顺序 ≠ 物理顺序**:数据库优化器会根据索引、统计信息调整实际执行计划[^3]。 - **别名生效时机**:`SELECT`阶段定义的别名只能在`ORDER BY`/`HAVING`之后使用[^4]。 - **聚合函数位置**: - `WHERE`中**不可**用聚合(因分组未发生) - `HAVING`中**必须**用聚合(因过滤的是分组结果) --- ### 示例验证 ```sql SELECT d.dept_name, AVG(e.salary) AS avg_salary -- (7) FROM employees e -- (1) JOIN departments d ON e.dept_id = d.id -- (2)(3) WHERE e.hire_date > '2020-01-01' -- (4) GROUP BY d.dept_name -- (5) HAVING AVG(e.salary) > 8000 -- (6) ORDER BY avg_salary DESC -- (9) LIMIT 3; -- (10) ``` *执行顺序编号对应上文流程图。* --- ###
评论 9
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值