Published on

sql语句执行顺序及各阶段注意点

Authors

简要版:

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
)

详细体会可通过该连接做题感受,以上sql是题解

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的记录进行计数。

详细体会可通过该连接做题感受,以上sql是题解

例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

详细体会可通过该连接做题感受,以上sql是题解

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/