- Published on
sql语句执行顺序及各阶段注意点
- Authors
- Name
- Yanbin
- @ybtaimu
简要版:
1.from:需要从哪个数据表检索数据。
2.where:过滤表中数据的条件。
3.group by:如何将上⾯过滤出的数据分组 。
4.having:对上⾯已经分组的数据进⾏过滤的条件。
5.select:查看结果集中的哪个列,或列的计算结果。
6.order by :按照什么样的顺序来查看返回的数据。
先执行on,后执行where;on是建立关联关系在生成临时表时候执行,where是在临时表生成后对数据进行筛选的。
详细版:
1.from (两表做笛卡尔积,生成临时表temp1)
2.on (根据条件对temp1进行筛选生成临时表temp2)
3.join (根据JOIN的类型不同来对虚表tmp2做行的增减, 如果是LEFT (OUTER) JOIN就把上一步舍弃的左表的记录补回来,对应右表的数据用NULL填充; 如果是RIGHT(OUTER) JOIN的话就把右表删除的记录补回来, 同理FULL (OUTER) JOIN分别做类似的增加记录操作, 但是(INNER) JOIN不会, 所以这一步的操作主要针对的是OUTER JOIN。 形成虚表temp3)
- 若 from 子句中的表数目多余两个表,那么就将temp3和第三个表连接从而计算笛卡尔乘积,生成虚拟表,该过程就是一个重复1-3的步骤,最终得到一个新的虚拟表 temp3。
4.where (应用where筛选器,对上一步生产的虚拟表引用where筛选器,生成虚拟表temp4)
5.group by(group by 子句将中的唯一的值组合成为一组,得到虚拟表temp5.开始使用select中的别名,后面的语句中都可以使用)
- group by
后面可以 是 多列
,用逗号分隔
- 虚拟表时不汇总为一行,但整个sql执行完最终输出时只输出单行记录
6.avg,sum.... (应用avg或者sum选项,为temp5生成超组,生成temp6.此时对分完组的数据 合并为一条记录,在合并过程中通过sql聚合函数处理)
任何聚合函数都会在这个阶段执行,不管函数书写位置在SQL中的SELECT之后还是在HAVING之后!
。详见聚合函数将来自多行的数据汇总到单个结果行中
有别于窗口函数
聚合函数是要显示的记录的该列的值做处理,而不是对记录做筛选
,例如MIN
函数,会针对一组记录的某一列,使得要显示的那条记录的该列显示为该组所有列中的最小值等。聚合函数 自带GROUP BY效果
,哪怕不写GROUP BY,当使用SUM等聚合函数时,默认做分组聚合处理。所以当多条记录的表的其中一列求SUM等操作时,会做分组聚合处理,最终结果输出为1条记录。
例:
SELECT (
ROUND(AVG(IF(order_date = customer_pref_delivery_date,1,0))*100,2)
) AS immediate_percentage
FROM Delivery
WHERE (customer_id,order_date) IN (
SELECT customer_id,MIN(order_date)
FROM Delivery
GROUP BY
customer_id
)
7.having (应用having筛选器,生成temp7。having筛选器是第一个也是为唯一一个应用到已分组数据
的筛选器,重点是针对已分组的)
书写时写在HAVING之后的聚合函数(例如COUNT函数)。
执行时COUNT
时,还是使用的未合并成一条记录的数据
。总结:不管聚合函数写在哪,若是语句中有聚合函数,则总是在GROUP BY之后执行HAVING子句是配合GROUP BY
使用的,单独使用HAVING本身是不符合规范.若是单独使用,MySQL会做一个重写,加上一个GROUP BY NULL,GROUP BY NULL 等价于 LIMIT 1
。当GROUP BY NULL的时候,MAX/MIN函数是取所有数据里的最大和最小值
8.select (将temp7中的在select中出现的列筛选出来,生成temp8)
9.distinct (做指定列的去重操作,生成temp9)
不对表使用
group by
如何统计某表的某种分类的总数量
,可以通过DISTINCT 分类去重
一般而言,
DISTINCT子句是GROUP BY子句的特殊情况
。 DISTINCT子句和GROUP BY子句之间的区别是GROUP BY子句可对结果集进行排序,而DISTINCT子句不进行排序。 [更多请阅读]:(https://www.yiibai.com/mysql/distinct.html)
例1:
SELECT teacher_id,COUNT(DISTINCT subject_id) AS cnt
FROM Teacher
GROUP BY
teacher_id
重点在于 COUNT(DISTINCT subject_id)
。
该sql简要执行过程如下:
(1). 先进行 GROUP BY 分组
(2). 执行聚合函数COUNT(),因其有DISTINCT
关键字,遂 通过 DISTINCT 对已分类的不同类的虚拟表,根据目标字段对虚拟表记录进行去重操作。 该示例中的DISTINCT执行顺序为什么会直接对仍是分组中的数据进行操作,而不是对已分组后的数据操作, 这是因为distinct在聚合函数count中,按照聚合函数的执行顺序去执行
。如果是单独的DISTINCT,不在聚合函数中,则按原顺序执行
(2).执行COUNT,对已经DISTINCT的记录进行计数。
例2:
SELECT IFNULL(ROUND(COUNT(DISTINCT(result.player_id)) /
(SELECT COUNT(DISTINCT(Activity.player_id)) FROM Activity)
,2),0) AS fraction
FROM (
SELECT Activity.player_id as player_id
FROM Activity
LEFT JOIN
(
SELECT player_id,MIN(event_date) AS f_data
FROM Activity
GROUP BY player_id
) AS f_ac
ON Activity.player_id = f_ac.player_id
WHERE DATEDIFF(Activity.event_date,f_ac.f_data) = 1
) AS result
10.order by (指定的列进行排序,生成temp10)
- order by
后面可以 是 多列
,用逗号分隔
11.limit (对已经做完各种操作后的结果集做限制输出)
写法注意点
sql 语句大小写规范:
1.关键字,函数名全都大写;
2.数据库名,表名,字段名称全部小写
3.sql语句必须分号结尾
使用注意点
1.inner join 和 outer join 的区别
2.INNER JOIN 只返回匹配的行,而 OUTER JOIN 返回所有行,包括匹配的行和不匹配的行。
3.怎么理解 BOOLEAN expression ? it returns either 1 or 0.
4.COUNT 会对 0 计数。 所以使用表达式后需要用OR NULL。使得返回值从0变为NULL.这样就不会被COUNT 统计。
Quote:
https://blog.csdn.net/u014044812/article/details/51004754
https://juejin.cn/post/6850418117764628487?from=search-suggest
https://www.wandersky.org/program/sql-must-know/2022/10/05/2690/