当前位置: 首页 > news >正文

SQL进阶:深入解析SQL执行顺序

SQL 的执行顺序是理解查询逻辑、排查语法错误和优化性能的核心基础。与 SQL 语句的书写顺序不同,数据库引擎会按照固定的内部逻辑分步执行,每一步的结果都会作为下一步的输入。以下从 “书写顺序 vs 执行顺序”“详细执行步骤”“关键注意事项” 三个维度,详解标准 SQL 的执行顺序。

一、书写顺序 vs 执行顺序:先 “敌后” 后 “正面”

SQL 语句的书写顺序通常是 “从外到内”(如SELECT在前,FROM紧随其后),但执行顺序却是 “从内到外”(先确定数据来源,再筛选、计算、输出)。

典型书写顺序(以SELECT查询为例):

SELECT [DISTINCT] 列名/表达式  -- 6. 确定最终返回的列
FROM 表名                      -- 1. 确定数据来源
JOIN 关联表 ON 关联条件        -- 1. (扩展数据来源:多表关联)
WHERE 过滤条件                 -- 2. 过滤行
GROUP BY 分组字段              -- 3. 按字段分组
HAVING 分组过滤条件            -- 4. 过滤分组
ORDER BY 排序字段              -- 5. 对结果排序
LIMIT 分页参数                 -- 7. 限制返回行数(非标准SQL,数据库扩展)

实际执行顺序(核心步骤):

  1. FROM / JOIN → 2. WHERE → 3. GROUP BY → 4. HAVING → 5. SELECT → 6. DISTINCT → 7. ORDER BY → 8. LIMIT

二、详细执行步骤:每一步做什么?

1. FROM / JOIN:确定数据来源,生成初始数据集
  • 作用:从指定表或视图中获取原始数据,若有JOIN,则通过关联条件将多表数据组合成 “临时结果集”(包含所有匹配的行)。
  • 细节
    • 先执行FROM后的主表,再依次执行JOIN关联的表(INNER JOIN/LEFT JOIN等),关联逻辑按书写顺序处理(但数据库优化器可能调整顺序以提升效率)。
    • 关联后的结果集包含所有表的字段(可能有重复列名,需用表别名区分)。

示例

SELECT u.user_id, o.order_id
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id;

执行逻辑:先获取users表的所有行,再通过user_id关联orders表,生成包含两表所有字段的临时结果集(users表无匹配的行,orders字段为NULL)。

2. WHERE:过滤行,保留符合条件的记录
  • 作用:对FROM/JOIN生成的临时结果集进行行过滤,只保留满足WHERE条件的记录。
  • 限制
    • 不能使用SELECT中定义的列别名(因WHERE执行早于SELECT,别名尚未生效)。
    • 不能使用聚合函数(如SUM()COUNT()),聚合函数需在GROUP BY后使用。

示例

SELECT u.user_id, o.order_id
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
WHERE u.age > 18;  -- 只保留年龄>18的用户记录

执行逻辑:在关联后的临时结果集中,过滤出users.age > 18的行。

3. GROUP BY:按字段分组,聚合数据
  • 作用:将WHERE过滤后的结果集按GROUP BY后的字段分组,每组视为一个整体,后续聚合函数(如SUM)将基于组内数据计算。
  • 关键规则
    • GROUP BY后的字段必须是SELECT中未使用聚合函数的字段(“非聚合字段必须在GROUP BY中”),否则会报错。
    • 分组后,结果集的行数等于分组的数量(如按user_id分组,行数等于不同user_id的数量)。

示例

SELECT u.user_id, SUM(o.amount) AS total  -- 聚合函数SUM基于分组计算
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
WHERE u.age > 18
GROUP BY u.user_id;  -- 按user_id分组,每组计算总金额

执行逻辑:将过滤后的结果按user_id分组,每组内的amount求和,生成 “每个用户的总消费” 结果集。

4. HAVING:过滤分组,保留符合条件的组
  • 作用:对GROUP BY后的分组结果进行过滤,只保留满足HAVING条件的分组(类似WHERE,但HAVING作用于分组,WHERE作用于行)。
  • 特点
    • 可以使用聚合函数(因HAVING执行于GROUP BY之后,聚合结果已生成)。
    • 可以使用SELECT中定义的聚合函数别名(如total)。

示例

SELECT u.user_id, SUM(o.amount) AS total
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
WHERE u.age > 18
GROUP BY u.user_id
HAVING total > 1000;  -- 只保留总消费>1000的用户分组

执行逻辑:在分组后的结果中,过滤出total > 1000的分组。

5. SELECT:确定返回的列或表达式
  • 作用:从前面步骤生成的结果集中,选择需要返回的列、计算表达式或聚合结果,并为其指定别名(如SUM(amount) AS total)。
  • 注意
    • 此时才会解析列别名(因此WHERE中不能使用别名,HAVINGORDER BY中可以)。
    • 若有GROUP BYSELECT中只能包含GROUP BY的字段和聚合函数。

示例

SELECT u.user_id AS uid,  -- 定义别名uidSUM(o.amount) AS total  -- 定义聚合结果别名total
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
WHERE u.age > 18
GROUP BY u.user_id
HAVING total > 1000;

执行逻辑:从过滤后的分组结果中,选择user_id(并重命名为uid)和total作为返回列。

6. DISTINCT:去重,保留唯一记录
  • 作用:对SELECT返回的结果集进行去重,删除完全相同的行(所有列值均相同的行)。
  • 注意
    • DISTINCT作用于所有选中的列,而非单个列(如SELECT DISTINCT a, b会基于ab的组合去重)。
    • 执行效率较低(需排序或哈希去重),非必要不使用。

示例

SELECT DISTINCT u.user_id  -- 去重,保留唯一的user_id
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id;
7. ORDER BY:对结果集排序
  • 作用:按指定字段对SELECT返回的结果集排序(ASC升序,DESC降序,默认升序)。
  • 特点
    • 可以使用SELECT中定义的列别名(因ORDER BY执行于SELECT之后)。
    • 可以使用未在SELECT中出现的字段(但不推荐,易导致逻辑混乱)。
    • 排序会消耗资源(尤其大数据量时),若无必要可省略。

示例

SELECT u.user_id AS uid, SUM(o.amount) AS total
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
GROUP BY u.user_id
HAVING total > 1000
ORDER BY total DESC;  -- 按total降序排序
8. LIMIT / OFFSET:限制返回行数(数据库扩展)
  • 作用:仅返回排序后结果集中的前 N 行,或从第 M 行开始的 N 行(分页查询),属于数据库扩展(非标准 SQL,但主流数据库均支持)。
  • 注意:必须配合ORDER BY使用,否则返回的行是随机的(无排序时 “前 N 行” 无意义)。

示例

SELECT u.user_id AS uid, SUM(o.amount) AS total
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
GROUP BY u.user_id
HAVING total > 1000
ORDER BY total DESC
LIMIT 10 OFFSET 20;  -- 返回第21-30行(分页)

三、关键注意事项:为什么会踩坑?

  1. 列别名的可见性

    • WHERE中不能用别名(执行顺序早于SELECT),需用原始字段或表达式。
    • ❌ 错误:WHERE uid > 100uidSELECT中定义的别名)
    • ✅ 正确:WHERE u.user_id > 100
    • HAVINGORDER BY中可以用别名(执行顺序晚于SELECT)。
  2. 聚合函数的使用范围

    • WHERE中不能用聚合函数(如WHERE SUM(amount) > 1000),需用HAVING
    • GROUP BY后,SELECT中只能出现GROUP BY字段和聚合函数(否则报错)。
  3. DISTINCTORDER BY的冲突

    • ORDER BY使用了未在SELECT中出现的字段,且同时使用DISTINCT,可能导致排序逻辑异常(不同数据库处理方式不同),需避免。
  4. 数据库优化器的影响

    • 上述执行顺序是逻辑上的步骤,实际中数据库优化器可能调整步骤(如提前过滤、调整JOIN顺序)以提升效率,但最终结果与逻辑顺序一致。

四、总结

SQL 的执行顺序是 “从数据来源到结果输出” 的层层处理:FROMJOIN(获取数据)→WHERE(过滤行)→GROUP BY(分组)→HAVING(过滤组)→SELECT(选列)→DISTINCT(去重)→ORDER BY(排序)→LIMIT(限制行数)。

理解这一顺序,能帮你:

  • 快速定位语法错误(如WHERE中用了别名);
  • 优化查询性能(如在WHERE中提前过滤,减少GROUP BY的数据量);
  • 清晰拆解复杂查询的逻辑(从内到外逐步分析)。
http://www.dtcms.com/a/521040.html

相关文章:

  • 专业网站建设的公司哪家好合肥计算机培训机构
  • C#实现摄像头视频录制与保存
  • 东莞网站建没可信网站是什么意思
  • led行业网站源码wordpress会员查看发布插件
  • 网站建设前期需要干嘛许昌网站建设哪家最好
  • 【Linux学习笔记】基于阻塞队列和环形队列的生产者消费者模型
  • GAN生成对抗网络学习-例子:生成逼真手写数字图
  • WPF MVVM下 ItemsControl条目命令绑定传参
  • 贵州网站制作公司电话wordpress有留言时邮件提醒
  • Python 脚本在工作日(周一到周五)的 8:00 到 19:00 之间持续运行,并在其他时间暂停(延时)
  • 婚庆网站大全深圳企业网站制作公司查询
  • 当城市有了“空间智能体”:一座长江首城的智慧蝶变
  • 机械类做的最好的网站网站开发代理江苏
  • 让别人做网站图片侵权网站简易后台
  • seo针对网站做策划大型网站开发合同
  • Macao资料生成程序,全新的UI 三端自适应PHP空间
  • 1Panel 安装与使用全指南:从部署到实战运维
  • Katalon Studio自愈测试功能
  • 非java、python、c/c++、perl、php、sql等的文章
  • 企业网站的建设与应用开题报告自己搭建app
  • 实验三:3-8线译码器设计
  • 深入浅出:马尔科夫链完全指南
  • 国外域名抢注网站seo顾问什么职位
  • 怎么做网站dns加速销售订单管理系统软件
  • DevOps工具链选型,Atlassian or TikLab哪一款更好用?
  • 网站实现搜索功能网站开发 平面设计
  • 河北建设厅官网站首页手机兼职有哪些
  • 【经典书籍】C++ Primer 第16章模板与泛型编程精华讲解
  • 做体育的网站网络推广优化是干啥的
  • 自己人网站建设网站推广策划方案大数据精准获客