东莞高端网站建设费用,上海网站建设 中华企业录,做网站的而程序,班级网站布局文章目录 1 聚合函数介绍1.1 AVG和SUM函数1.2 MIN和Max函数1.3 COUNT函数演示代码 2 GROUP BY2.1 基本使用2.2 使用多个列分组2.3 演示代码 3 HAVING3.1 基本使用3.2 WHERE和HAVING的对比3.3 演示代码 4 SELECT的执行过程4.1 查询的结构4.2 SELECT执行顺序4.3 SQL的执行原理演示… 文章目录 1 聚合函数介绍1.1 AVG和SUM函数1.2 MIN和Max函数1.3 COUNT函数演示代码 2 GROUP BY2.1 基本使用2.2 使用多个列分组2.3 演示代码 3 HAVING3.1 基本使用3.2 WHERE和HAVING的对比3.3 演示代码 4 SELECT的执行过程4.1 查询的结构4.2 SELECT执行顺序4.3 SQL的执行原理演示代码 课后练习 上一章讲到了 SQL 单行函数。实际上 SQL 函数还有一类叫做聚合或聚集、分组函数它是对一组数据进行汇总的函数输入的是一组数据的集合输出的是单个值。 1 聚合函数介绍
什么是聚合函数 聚合函数作用于一组数据并对一组数据返回一个值。 聚合函数类型
AVG()SUM()MAX()MIN()COUNT()
聚合函数语法 注意 聚合函数不能嵌套调用。比如不能出现类似“AVG(SUM(字段名称))”形式的调用。 1.1 AVG和SUM函数
可以对数值型数据使用AVG 和 SUM 函数。 SELECT AVG(salary), MAX(salary),MIN(salary), SUM(salary) FROM employees WHERE job_id LIKE %REP%;
/*
----------------------------------------------------
| AVG(salary) | MAX(salary) | MIN(salary) | SUM(salary) |
----------------------------------------------------
| 8272.727273 | 11500.00 | 6000.00 | 273000.00 |
----------------------------------------------------
*/1.2 MIN和Max函数
可以对任意数据类型的数据使用 MIN 和 MAX 函数。
SELECT MIN(hire_date), MAX(hire_date)
FROM employees;
/*
--------------------------------
| MIN(hire_date) | MAX(hire_date) |
--------------------------------
| 1987-06-17 | 2000-04-21 |
--------------------------------
*/1.3 COUNT函数
COUNT(*)返回表中记录总数适用于任意数据类型。
SELECT COUNT(*)
FROM employees
WHERE department_id 50;
/*
----------
| COUNT(*) |
----------
| 45 |
----------
*/
COUNT(expr) 返回expr不为空的记录总数。
SELECT COUNT(commission_pct)
FROM employees
WHERE department_id 50;
/*
-----------------------
| COUNT(commission_pct) |
-----------------------
| 0 |
-----------------------
*/问题用count( * )count(1)count(列名)谁好呢? 其实对于MyISAM引擎的表是没有区别的。这种引擎内部有一计数器在维护着行数。
Innodb引擎的表用count(* ),count(1)直接读行数复杂度是O(n)因为innodb真的要去数一遍。但好于具体的count(列名)。
问题能不能使用count(列名)替换count( * )? 不要使用 count(列名)来替代 count(* ) count(* ) 是 SQL92 定义的标准统计行数的语法跟数据库无关跟 NULL 和非 NULL 无关。 说明count(* )会统计值为 NULL 的行而 count(列名)不会统计此列为 NULL 值的行。
演示代码
#1. 常见的几个聚合函数
#1.1 AVG / SUM 只适用于数值类型的字段或变量SELECT AVG(salary),SUM(salary),AVG(salary) * 107
FROM employees;
/*输出
---------------------------------------------
| AVG(salary) | SUM(salary) | AVG(salary) * 107 |
---------------------------------------------
| 6461.682243 | 691400.00 | 691400.000000 |
---------------------------------------------
*/
#如下的操作没有意义
SELECT SUM(last_name),AVG(last_name),SUM(hire_date)
FROM employees;#1.2 MAX / MIN :适用于数值类型、字符串类型、日期时间类型的字段或变量
SELECT MAX(salary),MIN(salary)
FROM employees;
/*输出
--------------------------
| MAX(salary) | MIN(salary) |
--------------------------
| 24000.00 | 2100.00 |
--------------------------
*/
SELECT MAX(last_name),MIN(last_name),MAX(hire_date),MIN(hire_date)
FROM employees;
/*输出
----------------------------------------------------------------
| MAX(last_name) | MIN(last_name) | MAX(hire_date) | MIN(hire_date) |
----------------------------------------------------------------
| Zlotkey | Abel | 2000-04-21 | 1987-06-17 |
----------------------------------------------------------------
*/#1.3 COUNT
# ① 作用计算指定字段在查询结构中出现的个数不包含NULL值的
SELECT COUNT(employee_id),COUNT(salary),COUNT(2 * salary),COUNT(1),COUNT(2),COUNT(*)
FROM employees ;
/*输出
------------------------------------------------------------------------------------
| COUNT(employee_id) | COUNT(salary) | COUNT(2 * salary) | COUNT(1) | COUNT(2) | COUNT(*) |
------------------------------------------------------------------------------------
| 107 | 107 | 107 | 107 | 107 | 107 |
------------------------------------------------------------------------------------
*/SELECT *
FROM employees;#如果计算表中有多少条记录如何实现
#方式1COUNT(*)
#方式2COUNT(1)
#方式3COUNT(具体字段) : 不一定对#② 注意计算指定字段出现的个数时是不计算NULL值的。
SELECT COUNT(commission_pct)#COUNT(具体字段)
FROM employees;
/*
-----------------------
| COUNT(commission_pct) |
-----------------------
| 35 |
-----------------------
*/
SELECT commission_pct#具体字段
FROM employees
WHERE commission_pct IS NOT NULL;
/* 35条记录
----------------
| commission_pct |
----------------
| 0.40 |
| 0.30 |
| 0.30 |
*/#③ 公式AVG SUM / COUNT有没有空值都成立
SELECT AVG(salary),SUM(salary)/COUNT(salary),
AVG(commission_pct),SUM(commission_pct)/COUNT(commission_pct),
SUM(commission_pct) / 107
FROM employees;
/*
-----------------------------------------------------------------------------------------------------------------------------------
| AVG(salary) | SUM(salary)/COUNT(salary) | AVG(commission_pct) | SUM(commission_pct)/COUNT(commission_pct) | SUM(commission_pct) / 107 |
-----------------------------------------------------------------------------------------------------------------------------------
| 6461.682243 | 6461.682243 | 0.222857 | 0.222857 | 0.072897 |
-----------------------------------------------------------------------------------------------------------------------------------
*/#需求查询公司中平均奖金率
#错误的
SELECT AVG(commission_pct)
FROM employees;#SUM也不考虑空值NULL
#正确的
SELECT SUM(commission_pct) / COUNT(IFNULL(commission_pct,0)),#等同于COUNT(IFNULL(commission_pct,1/2/3/4/))
AVG(IFNULL(commission_pct,0))
FROM employees;
/*输出
--------------------------------------------------------------------------------------
| SUM(commission_pct) / COUNT(IFNULL(commission_pct,0)) | AVG(IFNULL(commission_pct,0)) |
--------------------------------------------------------------------------------------
| 0.072897 | 0.072897 |
--------------------------------------------------------------------------------------
*/# 如何需要统计表中的记录数使用COUNT(*)、COUNT(1)\COUNT(常数)、COUNT(具体字段) 哪个效率更高呢
# 如果使用的是MyISAM 存储引擎则三者效率相同时间复杂度都是O(1)
# 如果使用的是InnoDB 存储引擎则三者效率COUNT(*) COUNT(1) COUNT(字段)2 GROUP BY
2.1 基本使用 可以使用GROUP BY子句将表中的数据分成若干组
SELECT column, group_function(column)
FROM table
[WHERE condition]
[GROUP BY group_by_expression]
[ORDER BY column];明确WHERE一定放在FROM后面 在SELECT列表中所有未包含在组函数中的列都应该包含在 GROUP BY子句中
SELECT department_id, AVG(salary)
FROM employees
GROUP BY department_id ;
/*
-----------------------------
| department_id | AVG(salary) |
-----------------------------
| NULL | 7000.000000 |
| 10 | 4400.000000 |
| 20 | 9500.000000 |
| 30 | 4150.000000 |
| 40 | 6500.000000 |
| 50 | 3475.555556 |
| 60 | 5760.000000 |
| 70 | 10000.000000 |
| 80 | 8955.882353 |
| 90 | 19333.333333 |
| 100 | 8600.000000 |
| 110 | 10150.000000 |
-----------------------------
*/包含在 GROUP BY 子句中的列不必包含在SELECT 列表中
SELECT AVG(salary) FROM employees
GROUP BY department_id ;
/*
--------------
| AVG(salary) |
--------------
| 7000.000000 |
| 4400.000000 |
| 9500.000000 |
| 4150.000000 |
| 6500.000000 |
| 3475.555556 |
| 5760.000000 |
| 10000.000000 |
| 8955.882353 |
| 19333.333333 |
| 8600.000000 |
| 10150.000000 |
--------------
*/2.2 使用多个列分组 SELECT department_id dept_id, job_id, SUM(salary)
FROM employees
GROUP BY department_id, job_id ;
/*
----------------------------------
| dept_id | job_id | SUM(salary) |
----------------------------------
| NULL | SA_REP | 7000.00 |
| 10 | AD_ASST | 4400.00 |
| 20 | MK_MAN | 13000.00 |
| 20 | MK_REP | 6000.00 |
| 30 | PU_CLERK | 13900.00 |
| 30 | PU_MAN | 11000.00 |
| 40 | HR_REP | 6500.00 |
| 50 | SH_CLERK | 64300.00 |
| 50 | ST_CLERK | 55700.00 |
| 50 | ST_MAN | 36400.00 |
| 60 | IT_PROG | 28800.00 |
| 70 | PR_REP | 10000.00 |
| 80 | SA_MAN | 61000.00 |
| 80 | SA_REP | 243500.00 |
| 90 | AD_PRES | 24000.00 |
| 90 | AD_VP | 34000.00 |
| 100 | FI_ACCOUNT | 39600.00 |
| 100 | FI_MGR | 12000.00 |
| 110 | AC_ACCOUNT | 8300.00 |
| 110 | AC_MGR | 12000.00 |
----------------------------------
*/使用 WITH ROLLUP 关键字之后在所有查询出的分组记录之后增加一条记录该记录计算查询出的所有记录的总和即统计记录数量。
SELECT department_id,AVG(salary)
FROM employees
WHERE department_id 80
GROUP BY department_id WITH ROLLUP;
/*
-----------------------------
| department_id | AVG(salary) |
-----------------------------
| 90 | 19333.333333 |
| 100 | 8600.000000 |
| 110 | 10150.000000 |
| NULL | 11809.090909 |
-----------------------------
*/注意 当使用ROLLUP时不能同时使用ORDER BY子句进行结果排序即ROLLUP和ORDER BY是互相排斥的。 2.3 演示代码
#其他方差、标准差、中位数
#2. GROUP BY 的使用#需求查询各个部门的平均工资最高工资
SELECT department_id,AVG(salary),SUM(salary)
FROM employees
GROUP BY department_id
/*输出
------------------------------------------
| department_id | AVG(salary) | SUM(salary) |
------------------------------------------
| NULL | 7000.000000 | 7000.00 |
| 10 | 4400.000000 | 4400.00 |
| 20 | 9500.000000 | 19000.00 |
| 30 | 4150.000000 | 24900.00 |
| 40 | 6500.000000 | 6500.00 |
| 50 | 3475.555556 | 156400.00 |
| 60 | 5760.000000 | 28800.00 |
| 70 | 10000.000000 | 10000.00 |
| 80 | 8955.882353 | 304500.00 |
| 90 | 19333.333333 | 58000.00 |
| 100 | 8600.000000 | 51600.00 |
| 110 | 10150.000000 | 20300.00 |
------------------------------------------
*/#需求查询各个job_id的平均工资
SELECT job_id,AVG(salary)
FROM employees
GROUP BY job_id;
/*输出
--------------------------
| job_id | AVG(salary) |
--------------------------
| AC_ACCOUNT | 8300.000000 |
| AC_MGR | 12000.000000 |
| AD_ASST | 4400.000000 |
| AD_PRES | 24000.000000 |
| AD_VP | 17000.000000 |
| FI_ACCOUNT | 7920.000000 |
| FI_MGR | 12000.000000 |
| HR_REP | 6500.000000 |
| IT_PROG | 5760.000000 |
| MK_MAN | 13000.000000 |
| MK_REP | 6000.000000 |
| PR_REP | 10000.000000 |
| PU_CLERK | 2780.000000 |
| PU_MAN | 11000.000000 |
| SA_MAN | 12200.000000 |
| SA_REP | 8350.000000 |
| SH_CLERK | 3215.000000 |
| ST_CLERK | 2785.000000 |
| ST_MAN | 7280.000000 |
--------------------------
*/#需求查询各个department_id,job_id的平均工资
#方式1
SELECT department_id,job_id,AVG(salary)
FROM employees
GROUP BY department_id,job_id;
/*部分输出
-----------------------------------------
| department_id | job_id | AVG(salary) |
-----------------------------------------
| NULL | SA_REP | 7000.000000 |
| 10 | AD_ASST | 4400.000000 |
| 20 | MK_MAN | 13000.000000 |
| 20 | MK_REP | 6000.000000 |
| 30 | PU_CLERK | 2780.000000 |
| 30 | PU_MAN | 11000.000000 |
| 40 | HR_REP | 6500.000000 |
| 50 | SH_CLERK | 3215.000000 |
*/
#方式2 方式1和方式2其实是一样的(都按job_id,department_id分组)
SELECT job_id,department_id,AVG(salary)
FROM employees
GROUP BY job_id,department_id;
/*部分输出
-----------------------------------------
| job_id | department_id | AVG(salary) |
-----------------------------------------
| AC_ACCOUNT | 110 | 8300.000000 |
| AC_MGR | 110 | 12000.000000 |
| AD_ASST | 10 | 4400.000000 |
| AD_PRES | 90 | 24000.000000 |
| AD_VP | 90 | 17000.000000 |
| FI_ACCOUNT | 100 | 7920.000000 |
| FI_MGR | 100 | 12000.000000 |
*/#错误的--SELECT的job_id字段没有在GROUP BY中出现故错误
#AVG(salary)中的salary出现在组函数中没有错
SELECT department_id,job_id,AVG(salary)
FROM employees
GROUP BY department_id;#只按department_id分组Oracle中报错
#由上面错误引出的结论
#结论1SELECT中出现的非组函数的字段必须声明在GROUP BY 中。
# 反之GROUP BY中声明的字段可以不出现在SELECT中。
#结论2GROUP BY 声明在FROM后面、WHERE后面ORDER BY 前面、LIMIT前面
#结论3MySQL中GROUP BY中可使用WITH ROLLUP#WITH ROLLUP举例
#WITH ROLLUP分完组后在末尾添加整体的组函数结果
#如下面例子中在末尾添加所有员工的AVG(salary) 6461.682243
SELECT department_id,AVG(salary)
FROM employees
GROUP BY department_id WITH ROLLUP;
/*
-----------------------------
| department_id | AVG(salary) |
-----------------------------
| NULL | 7000.000000 |
| 10 | 4400.000000 |
| 20 | 9500.000000 |
| 30 | 4150.000000 |
| 40 | 6500.000000 |
| 50 | 3475.555556 |
| 60 | 5760.000000 |
| 70 | 10000.000000 |
| 80 | 8955.882353 |
| 90 | 19333.333333 |
| 100 | 8600.000000 |
| 110 | 10150.000000 |
| NULL | 6461.682243 |
-----------------------------
*/#需求A查询各个部门的平均工资按照平均工资升序排列
SELECT department_id,AVG(salary) avg_sal
FROM employees
GROUP BY department_id
ORDER BY avg_sal ASC;
/*
-----------------------------
| department_id | avg_sal |
-----------------------------
| 50 | 3475.555556 |
| 30 | 4150.000000 |
| 10 | 4400.000000 |
| 60 | 5760.000000 |
| 40 | 6500.000000 |
| NULL | 7000.000000 |
| 100 | 8600.000000 |
| 80 | 8955.882353 |
| 20 | 9500.000000 |
| 70 | 10000.000000 |
| 110 | 10150.000000 |
| 90 | 19333.333333 |
-----------------------------
*/#接着需求A引出以下说明
#说明当使用ROLLUP时不能同时使用ORDER BY子句进行结果排序即ROLLUP和ORDER BY是互相排斥的。
#错误的
SELECT department_id,AVG(salary) avg_sal
FROM employees
GROUP BY department_id WITH ROLLUP
ORDER BY avg_sal ASC;结论
SELECT中出现的非组函数的字段必须声明在GROUP BY 中。 反之GROUP BY中声明的字段可以不出现在SELECT中。GROUP BY 声明在FROM后面、WHERE后面ORDER BY 前面、LIMIT前面MySQL中GROUP BY中可使用WITH ROLLUP
3 HAVING
3.1 基本使用 过滤分组HAVING子句
行已经被分组。使用了聚合函数。满足HAVING 子句中条件的分组将被显示。HAVING 不能单独使用必须要跟 GROUP BY 一起使用。 SELECT department_id, MAX(salary)
FROM employees
GROUP BY department_id
HAVING MAX(salary)10000 ;
/*
----------------------------
| department_id | MAX(salary) |
----------------------------
| 20 | 13000.00 |
| 30 | 11000.00 |
| 80 | 14000.00 |
| 90 | 24000.00 |
| 100 | 12000.00 |
| 110 | 12000.00 |
----------------------------
*/非法使用聚合函数 不能在 WHERE 子句中使用聚合函数。如下
SELECT department_id, AVG(salary)
FROM employees
WHERE AVG(salary) 8000
GROUP BY department_id;
#报错
#ERROR 1111 (HY000): Invalid use of group function3.2 WHERE和HAVING的对比
区别1 WHERE 可以直接使用表中的字段作为筛选条件但不能使用分组中的计算函数作为筛选条件HAVING 必须要与 GROUP BY 配合使用可以把分组计算的函数和分组字段作为筛选条件。
这决定了在需要对数据进行分组统计的时候HAVING 可以完成 WHERE 不能完成的任务。这是因为在查询语法结构中WHERE 在 GROUP BY 之前所以无法对分组结果进行筛选。HAVING 在 GROUP BY 之后可以使用分组字段和分组中的计算函数对分组的结果集进行筛选这个功能是 WHERE 无法完成的。另外WHERE排除的记录不再包括在分组中。
区别2如果需要通过连接从关联表中获取需要的数据WHERE 是先筛选后连接而 HAVING 是先连接后筛选。
这一点就决定了在关联查询中WHERE 比 HAVING 更高效。因为 WHERE 可以先筛选用一个筛选后的较小数据集和关联表进行连接这样占用的资源比较少执行效率也比较高。HAVING 则需要先把结果集准备好也就是用未被筛选的数据集进行关联然后对这个大的数据集进行筛选这样占用的资源就比较多执行效率也较低。
小结如下 开发中的选择 WHERE 和 HAVING 也不是互相排斥的可以在一个查询里面同时使用 WHERE 和 HAVING。包含分组统计函数的条件用 HAVING普通条件用 WHERE。这样就既利用了 WHERE 条件的高效快速又发挥了 HAVING 可以使用包含分组统计函数的查询条件的优点。当数据量特别大的时候运行效率会有很大的差别。
3.3 演示代码
#3. HAVING的使用 (作用用来过滤数据的)WHERE也是用于过滤
#练习查询各个部门中最高工资比10000高的部门信息
#错误的写法
SELECT department_id,MAX(salary)
FROM employees
WHERE MAX(salary) 10000#WHERE声明在FROM后
GROUP BY department_id;#要求1如果过滤条件中使用了聚合函数则必须使用HAVING来替换WHERE。否则报错。
#要求2HAVING 必须声明在 GROUP BY 的后面。
#正确的写法
SELECT department_id,MAX(salary)
FROM employees
GROUP BY department_id
HAVING MAX(salary) 10000;
#要求3开发中我们使用HAVING的前提是SQL中使用了GROUP BY。#练习查询部门id为10,20,30,40这4个部门中最高工资比10000高的部门信息
#方式1推荐执行效率高于方式2.
SELECT department_id,MAX(salary)
FROM employees
WHERE department_id IN (10,20,30,40)
GROUP BY department_id
HAVING MAX(salary) 10000;
/*
----------------------------
| department_id | MAX(salary) |
----------------------------
| 20 | 13000.00 |
| 30 | 11000.00 |
----------------------------
*/
#方式2
SELECT department_id,MAX(salary)
FROM employees
GROUP BY department_id
HAVING MAX(salary) 10000 AND department_id IN (10,20,30,40);
#结论当过滤条件中有聚合函数时则此过滤条件必须声明在HAVING中。
# 当过滤条件中没有聚合函数时则此过滤条件声明在WHERE中或HAVING中都可以。但是建议大家声明在WHERE中。/*WHERE 与 HAVING 的对比
1. 从适用范围上来讲HAVING的适用范围更广。
2. 如果过滤条件中没有聚合函数这种情况下WHERE的执行效率要高于HAVING
*/4 SELECT的执行过程
4.1 查询的结构
#方式1
SELECT ...,....,...
FROM ...,...,....
WHERE 多表的连接条件
AND 不包含组函数的过滤条件
GROUP BY ...,...
HAVING 包含组函数的过滤条件
ORDER BY ... ASC/DESC
LIMIT ...,...
#方式2
SELECT ...,....,...
FROM ... JOIN ...
ON 多表的连接条件
JOIN ...
ON ...
WHERE 不包含组函数的过滤条件
AND/OR 不包含组函数的过滤条件
GROUP BY ...,...
HAVING 包含组函数的过滤条件
ORDER BY ... ASC/DESC
LIMIT ...,...
#其中
#1from从哪些表中筛选
#2on关联多表查询时去除笛卡尔积
#3where从表中筛选的条件
#4group by分组依据
#5having在统计结果中再次筛选
#6order by排序
#7limit分页4.2 SELECT执行顺序
需要记住 SELECT 查询时的两个顺序
关键字的顺序是不能颠倒的 SELECT ... FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY ... LIMIT... SELECT 语句的执行顺序在 MySQL 和 Oracle 中SELECT 执行顺序基本相同 FROM - WHERE - GROUP BY - HAVING - SELECT 的字段 - DISTINCT - ORDER BY - LIMIT 比如写了一个 SQL 语句那么它的关键字顺序和执行顺序是下面这样的
SELECT DISTINCT player_id, player_name, count(*) as num # 顺序 5
FROM player JOIN team ON player.team_id team.team_id # 顺序 1
WHERE height 1.80 # 顺序 2
GROUP BY player.team_id # 顺序 3
HAVING num 2 # 顺序 4
ORDER BY num DESC # 顺序 6
LIMIT 2 # 顺序 7在 SELECT 语句执行这些步骤的时候每个步骤都会产生一个 虚拟表 然后将这个虚拟表传入下一个步骤中作为输入。需要注意的是这些步骤隐含在 SQL 的执行过程中对于我们来说是不可见的。
4.3 SQL的执行原理
SELECT 是先执行 FROM 这一步的。在这个阶段如果是多张表联查还会经历下面的几个步骤
首先先通过 CROSS JOIN 求笛卡尔积相当于得到虚拟表 vtvirtual table1-1通过 ON进行筛选在虚拟表 vt1-1 的基础上进行筛选得到虚拟表 vt1-2添加外部行。如果我们使用的是左连接、右链接或者全连接就会涉及到外部行也就是在虚拟表 vt1-2 的基础上增加外部行得到虚拟表vt1-3。
当然如果我们操作的是两张以上的表还会重复上面的步骤直到所有表都被处理完为止。这个过程得到是我们的原始数据。
当我们拿到了查询数据表的原始数据也就是最终的虚拟表 vt1 就可以在此基础上再进行 WHERE 阶段 。在这个阶段中会根据 vt1 表的结果进行筛选过滤得到虚拟表 vt2 。
然后进入第三步和第四步也就是 GROUP 和 HAVING 阶段 。在这个阶段中实际上是在虚拟表 vt2 的基础上进行分组和分组过滤得到中间的虚拟表 vt3 和 vt4 。
当我们完成了条件筛选部分之后就可以筛选表中提取的字段也就是进入到 SELECT 和 DISTINCT 阶段。
首先在 SELECT 阶段会提取想要的字段然后在 DISTINCT 阶段过滤掉重复的行分别得到中间的虚拟表 vt5-1 和 vt5-2 。
当我们提取了想要的字段数据之后就可以按照指定的字段进行排序也就是 ORDER BY 阶段 得到虚拟表 vt6 。
最后在 vt6 的基础上取出指定行的记录也就是 LIMIT 阶段 得到最终的结果对应的是虚拟表vt7 。
当然在写 SELECT 语句的时候不一定存在所有的关键字相应的阶段就会省略。同时因为 SQL 是一门类似英语的结构化查询语言所以我们在写 SELECT 语句的时候还要注意相应的关键字顺序所谓底层运行的原理就是我们刚才讲到的执行顺序。
演示代码
#4. SQL底层执行原理
#4.1 SELECT 语句的完整结构
/*
#sql92语法
SELECT ....,....,....(存在聚合函数)
FROM ...,....,....
WHERE 多表的连接条件 AND 不包含聚合函数的过滤条件
GROUP BY ...,....
HAVING 包含聚合函数的过滤条件
ORDER BY ....,...(ASC / DESC )
LIMIT ...,....#sql99语法
SELECT ....,....,....(存在聚合函数)
FROM ... (LEFT / RIGHT)JOIN ....ON 多表的连接条件
(LEFT / RIGHT)JOIN ... ON ....
WHERE 不包含聚合函数的过滤条件
GROUP BY ...,....
HAVING 包含聚合函数的过滤条件
ORDER BY ....,...(ASC / DESC )
LIMIT ...,....
*/#4.2 SQL语句的执行过程
#FROM ...,...- ON - (LEFT/RIGNT JOIN) - WHERE - GROUP BY - HAVING - SELECT - DISTINCT -
# ORDER BY - LIMIT课后练习
# 第08章_聚合函数的课后练习
#1.where子句可否使用组函数进行过滤? No!#2.查询公司员工工资的最大值最小值平均值总和
SELECT MAX(salary) max_sal ,MIN(salary) mim_sal,AVG(salary) avg_sal,SUM(salary) sum_sal
FROM employees;
/*输出
-------------------------------------------
| max_sal | mim_sal | avg_sal | sum_sal |
-------------------------------------------
| 24000.00 | 2100.00 | 6461.682243 | 691400.00 |
-------------------------------------------
*/#3.查询各job_id的员工工资的最大值最小值平均值总和
SELECT job_id,MAX(salary),MIN(salary),AVG(salary),SUM(salary)
FROM employees
GROUP BY job_id;
/*部分输出
-----------------------------------------------------------------
| job_id | MAX(salary) | MIN(salary) | AVG(salary) | SUM(salary) |
-----------------------------------------------------------------
| AC_ACCOUNT | 8300.00 | 8300.00 | 8300.000000 | 8300.00 |
| AC_MGR | 12000.00 | 12000.00 | 12000.000000 | 12000.00 |
| AD_ASST | 4400.00 | 4400.00 | 4400.000000 | 4400.00 |
| AD_PRES | 24000.00 | 24000.00 | 24000.000000 | 24000.00 |
*/#4.选择具有各个job_id的员工人数
SELECT job_id,COUNT(*)
FROM employees
GROUP BY job_id;
/*部分输出
----------------------
| job_id | COUNT(*) |
----------------------
| AC_ACCOUNT | 1 |
| AC_MGR | 1 |
| AD_ASST | 1 |
| AD_PRES | 1 |
| AD_VP | 2 |
| FI_ACCOUNT | 5 |
*/# 5.查询员工最高工资和最低工资的差距DIFFERENCE #DATEDIFF
SELECT MAX(salary) - MIN(salary) DIFFERENCE
FROM employees;
/*
------------
| DIFFERENCE |
------------
| 21900.00 |
------------
*/# 6.查询各个管理者手下员工的最低工资其中最低工资不能低于6000没有管理者的员工不计算在内
SELECT manager_id,MIN(salary)
FROM employees
WHERE manager_id IS NOT NULL
GROUP BY manager_id
HAVING MIN(salary) 6000;
/*输出
-------------------------
| manager_id | MIN(salary) |
-------------------------
| 102 | 9000.00 |
| 108 | 6900.00 |
| 145 | 7000.00 |
| 146 | 7000.00 |
| 147 | 6200.00 |
| 148 | 6100.00 |
| 149 | 6200.00 |
| 201 | 6000.00 |
| 205 | 8300.00 |
-------------------------
*/# 7.查询所有部门的名字location_id员工数量和平均工资并按平均工资降序
SELECT department_name, location_id, COUNT(employee_id), AVG(salary) avg_sal
FROM employees e RIGHT JOIN departments d
ON e.department_id d.department_id
GROUP BY department_name, location_id
ORDER BY avg_sal DESC;
/*
部分输出
---------------------------------------------------------------------
| department_name | location_id | COUNT(employee_id) | avg_sal |
---------------------------------------------------------------------
| Executive | 1700 | 3 | 19333.333333 |
| Accounting | 1700 | 2 | 10150.000000 |
| Public Relations | 2700 | 1 | 10000.000000 |
*/# 8.查询每个工种、每个部门的部门名、工种名和最低工资
SELECT d.department_name,e.job_id,MIN(salary)
FROM departments d LEFT JOIN employees e
ON d.department_id e.department_id
GROUP BY department_name,job_id;
/*部分输出
-----------------------------------------------
| department_name | job_id | MIN(salary) |
-----------------------------------------------
| Accounting | AC_ACCOUNT | 8300.00 |
| Accounting | AC_MGR | 12000.00 |
| Administration | AD_ASST | 4400.00 |
| Benefits | NULL | NULL |
| Construction | NULL | NULL |
| Contracting | NULL | NULL |
*/