MySQL讲义第 32 讲——select 查询之 select 语句的执行顺序
SELECT 语句中各个子句的执行顺序与 SELECT 语句中子句的语法顺序是不一样的。
一、SELECT 语句的语法顺序
SELECT 语句在书写时各个关键字要保持下面的顺序:
select [distinct] 字段或表达式列表
from 表名 join(left join, right join) on 连接条件
where 筛选条件
group by 字段列表
having 字段列表
order by 字段列表
limit <m,n>
二、SELECT 语句的执行顺序
SELECT 语句中各个子句按照下面的顺序执行。每个子句执行后都会产生一个中间结果,供接下来的子句使用,如果不存在某个子句,就跳过该子句。
1. FROM子句
2. WHERE子句
3. GROUP BY子句
4. HAVING子句
5. SELECT子句
6. ORDER BY子句
7. LIMIT子句
/* ########################################################################################
执行顺序的说明:
(1) from 子句组装来自不同数据源的数据;
(2) where 子句基于指定的条件对记录行进行筛选;
(3) group by 子句将数据划分为多个分组;
(4) 使用聚集函数进行计算;
(5) 使用 having 子句筛选分组;
(6) 计算所有的表达式;
(7) select 字段;
(8) 使用 order by 对结果集进行排序。
关于字段别名的使用:
(1) WHERE子句不能使用字段别名。
(2) 从 GROUP BY 子句开始,后面的所有子句可以使用字段别名。
######################################################################################## */
三、执行过程模拟
后面的查询用到下面的两张表,表结构和数据如下:
mysql> select * from dept;
+---------+-----------+
| dept_id | dept_name |
+---------+-----------+
| 11 | 财务部 |
| 12 | 技术部 |
| 13 | 销售部 |
| 14 | 公关部 |
+---------+-----------+
4 rows in set (0.00 sec)
mysql> select * from emp;
+------+-----------+--------+----------+---------+
| e_id | e_name | gender | salary | dept_id |
+------+-----------+--------+----------+---------+
| 1101 | 张美华 | 女 | 5000.00 | 11 |
| 1102 | 王涛 | 男 | 5200.00 | 11 |
| 1103 | 张学有 | 男 | 4700.00 | 11 |
| 1201 | 刘得华 | 男 | 5200.00 | 12 |
| 1202 | 董雯花 | 女 | 5900.00 | 12 |
| 1203 | 宋族营 | 男 | 6500.00 | 12 |
| 1204 | 李霜江 | 男 | 7200.00 | 12 |
| 1301 | 梁美丽 | 女 | 7040.00 | 13 |
| 1302 | 王大强 | 男 | 6710.00 | 13 |
| 1303 | 张美华 | 女 | 8580.00 | 13 |
| 1304 | 赵紫龙 | 男 | 7590.00 | 13 |
| 1305 | 诸葛量 | 男 | 10120.00 | 13 |
| 1306 | 曹梦德 | 男 | 9240.00 | 13 |
+------+-----------+--------+----------+---------+
13 rows in set (0.00 sec)
1、使用 FROM 子句指定要查询的表,根据 select <字段列表>,得到一个中间表 vt1
mysql> SELECT
-> e.e_id,
-> e.e_name ename, --为 e_name 指定别名 ename
-> e.salary,
-> e.dept_id,
-> d.dept_name
-> FROM
-> emp e JOIN dept d ON e.dept_id = d.dept_id;
+------+-----------+----------+---------+-----------+
| e_id | ename | salary | dept_id | dept_name |
+------+-----------+----------+---------+-----------+
| 1101 | 张美华 | 5000.00 | 11 | 财务部 |
| 1102 | 王涛 | 5200.00 | 11 | 财务部 |
| 1103 | 张学有 | 4700.00 | 11 | 财务部 |
| 1201 | 刘得华 | 5200.00 | 12 | 技术部 |
| 1202 | 董雯花 | 5900.00 | 12 | 技术部 |
| 1203 | 宋族营 | 6500.00 | 12 | 技术部 |
| 1204 | 李霜江 | 7200.00 | 12 | 技术部 |
| 1301 | 梁美丽 | 7040.00 | 13 | 销售部 |
| 1302 | 王大强 | 6710.00 | 13 | 销售部 |
| 1303 | 张美华 | 8580.00 | 13 | 销售部 |
| 1304 | 赵紫龙 | 7590.00 | 13 | 销售部 |
| 1305 | 诸葛量 | 10120.00 | 13 | 销售部 |
| 1306 | 曹梦德 | 9240.00 | 13 | 销售部 |
+------+-----------+----------+---------+-----------+
13 rows in set (0.00 sec)
2、使用 WHERE 子句对中间表 vt1 进行筛选,得到中间表 vt2
注意:在 WHERE 子句中不能使用字段别名。
mysql> SELECT
-> e.e_id,
-> e.e_name ename,
-> e.salary,
-> e.dept_id,
-> d.dept_name
-> FROM
-> emp e JOIN dept d ON e.dept_id = d.dept_id
-> WHERE ename like '王%';
ERROR 1054 (42S22): Unknown column 'ename' in 'where clause'
---说明:出现错误!在 WHERE 子句中不能使用字段别名 ename。
mysql> SELECT
-> e.e_id,
-> e.e_name ename,
-> e.salary,
-> e.dept_id,
-> d.dept_name
-> FROM
-> emp e JOIN dept d ON e.dept_id = d.dept_id
-> WHERE
-> salary BETWEEN 5000 AND 10000;
+------+-----------+---------+---------+-----------+
| e_id | ename | salary | dept_id | dept_name |
+------+-----------+---------+---------+-----------+
| 1101 | 张美华 | 5000.00 | 11 | 财务部 |
| 1102 | 王涛 | 5200.00 | 11 | 财务部 |
| 1201 | 刘得华 | 5200.00 | 12 | 技术部 |
| 1202 | 董雯花 | 5900.00 | 12 | 技术部 |
| 1203 | 宋族营 | 6500.00 | 12 | 技术部 |
| 1204 | 李霜江 | 7200.00 | 12 | 技术部 |
| 1301 | 梁美丽 | 7040.00 | 13 | 销售部 |
| 1302 | 王大强 | 6710.00 | 13 | 销售部 |
| 1303 | 张美华 | 8580.00 | 13 | 销售部 |
| 1304 | 赵紫龙 | 7590.00 | 13 | 销售部 |
| 1306 | 曹梦德 | 9240.00 | 13 | 销售部 |
+------+-----------+---------+---------+-----------+
11 rows in set (0.00 sec)
3、对中间表 vt2 按照 dept_name 字段分组,统计每个部门的平均工资,得到中间表 vt3
mysql> SELECT
-> d.dept_name,
-> avg(salary) AS avg_salary
-> FROM
-> emp e JOIN dept d ON e.dept_id = d.dept_id
-> WHERE
-> salary BETWEEN 5000 AND 10000
-> GROUP BY
-> d.dept_name;
+-----------+-------------+
| dept_name | avg_salary |
+-----------+-------------+
| 技术部 | 6200.000000 |
| 财务部 | 5100.000000 |
| 销售部 | 7832.000000 |
+-----------+-------------+
3 rows in set (0.00 sec)
4、使用 HAVING 子句对中间表 vt3 进行筛选,得到中间表 vt4
mysql> SELECT
-> d.dept_name,
-> avg(salary) AS avg_salary
-> FROM
-> emp e JOIN dept d ON e.dept_id = d.dept_id
-> WHERE
-> salary BETWEEN 5000 AND 10000
-> GROUP BY
-> d.dept_name
-> HAVING
-> avg_salary > 6000; ---此处使用了表达式别名
+-----------+-------------+
| dept_name | avg_salary |
+-----------+-------------+
| 技术部 | 6200.000000 |
| 销售部 | 7832.000000 |
+-----------+-------------+
2 rows in set (0.01 sec)
5、使用 ORDER BY 子句对中间表 vt4 进行排序,得到中间表 vt5
mysql> SELECT
-> d.dept_name,
-> avg(salary) AS avg_salary
-> FROM
-> emp e JOIN dept d ON e.dept_id = d.dept_id
-> WHERE
-> salary BETWEEN 5000 AND 10000
-> GROUP BY
-> d.dept_name
-> HAVING
-> avg_salary > 6000
-> ORDER BY
-> avg_salary DESC;
+-----------+-------------+
| dept_name | avg_salary |
+-----------+-------------+
| 销售部 | 7832.000000 |
| 技术部 | 6200.000000 |
+-----------+-------------+
2 rows in set (0.00 sec)
6、使用 LIMIT 子句从中间表 vt5 中取出第一条记录,得到最终的结果表
mysql> SELECT
-> d.dept_name,
-> avg(salary) AS avg_salary
-> FROM
-> emp e JOIN dept d ON e.dept_id = d.dept_id
-> WHERE
-> salary BETWEEN 5000 AND 10000
-> GROUP BY
-> d.dept_name
-> HAVING
-> avg_salary > 6000
-> ORDER BY
-> avg_salary DESC
-> LIMIT
-> 1;
+-----------+-------------+
| dept_name | avg_salary |
+-----------+-------------+
| 销售部 | 7832.000000 |
+-----------+-------------+
1 row in set (0.00 sec)