聚合函数
1. 聚合函数
- 作用于一组数据,返回一个值
1.1 AVG() SUM()
- 对数值型数据使用
1.2 MIN() MAX()
- 对任意数据类型
SELECT AVG(salary), MAX(salary),MIN(salary), SUM(salary) FROM employees WHERE job_id LIKE '%REP%';
1.3 COUNT()
COUNT(*)和COUNT(1)相同,都是直接读行数,返回表中记录总数COUNT(expr)返回expr不为空的记录的总数
2. GROUP BY
- 将表中数据分组
2.1 使用多个列分组
- 按列的组合来分,多个列的话从左到右排
-- 先按department_id排,相同的则按job_id排
SELECT department_id, job_id, SUM(salary) FROM employees
GROUP BY department_id, job_id ;
2.2 GROUP BY 中使用 WITH ROLLUP
- 在最后新增一条记录,计算查询出的所有记录的总和
- 不能和 ORDER BY 同用
GROUP BY department_id WITH ROLLUP
3. HAVING
过滤分组
- 行已经被分组。
- 使用了聚合函数。
- 满足HAVING 子句中条件的分组将被显示。
- HAVING 不能单独使用,必须要跟 GROUP BY 一起使用。
SELECT department_id, MAX(salary) FROM employees
GROUP BY department_id HAVING MAX(salary)>10000 ;
3.1 WHERE 和 HAVING比较
多表连接,筛选和关联的顺序决定效率
4. SELECT 执行过程
4.1 执行过程
FROM -> WHERE -> GROUP BY -> HAVING -> SELECT 的字段 -> DISTINCT -> ORDER BY -> LIMIT
SELECT 语句执行这些步骤时,每个步骤都会产生一个虚拟表并传入下个步骤。
4.2 执行原理
- 先执行
FROM。如果是多表联查,还会经历下面的几个步骤:- 通过
CROSS JOIN求笛卡尔积,得到虚拟表 vt1-1; - 通过
ON筛选,在 vt1-1 的基础上进行筛选得到vt1-2; - 添加
外部行。如果我们使用的是左连接、右链接或者全连接。在 vt1-2 的基础上增加外部行,得到vt1-3。
- 通过
- 如果操作的是两张以上的表,还会重复上面的步骤,直到所有表都被处理完为止。这个过程得到是我们的原始数据。
- 拿到了查询数据表的原始数据 vt1 ,进行
WHERE阶段 。根据 vt1 表的结果进行筛选过滤,得到 vt2 。 GROUP和HAVING阶段 。在 vt2 的基础上进行分组和分组过滤,得到 vt3 和 vt4 。SELECT和DISTINCT阶段 。提取想要的字段后过滤掉重复的行,分别得到 vt5-1 和 vt5-2 。ORDER BY阶段 ,得到 vt6 。LIMIT阶段 ,取出指定行的记录 得到 vt7 。
子查询
1.子查询
查询中嵌套查询
- 子查询在主查询前执行完成。
注意事项- 子查询要包含在括号内
- 将子查询放在比较条件的右侧
- 单行操作符对应单行子查询,多行操作符对应多行子查询
1.1 子查询分类
- 子查询返回的记录数量
- 单行子查询
- 多行子查询
- 按子查询是否被多次执行
- 相关子查询
- 不相关子查询
2. 单行子查询
- 示例:返回公司中薪水最低的员工的姓名
SELECT last_name FROM employees
WHERE salary = (SELECT MIN(salary) FROM employees);
3. 多行子查询
3.1 多行比较操作符
- 示例:查询平均工资最低的部门Id
SELECT department_id FROM employees
GROUP BY department_id
HAVING AVG(salary) <= ALL (
SELECT AVG(salary) avg_sal FROM employees GROUP BY department_id
);
4. 相关子查询
- 子查询的执行依赖于外部查询,通常情况是因为子查询中的表用到了外部的表,并进行了条件关联,因此每执行一次外部查询,子查询都要重新计算一次。
示例:查询员工中 工资大于本部门平均工资 的员工 的名字
- 每查询一条记录都拿着该记录的
department_id进子查询筛选出相应部门的平均工资
SELECT last_name FROM employees outer
WHERE salary >
(SELECT AVG(salary) FROM employees WHERE department_id = outer.department_id);
4.1 EXISTS 与 NOT EXISTS关键字
- 关联子查询通常也会和 EXISTS操作符一起来使用,用来检查在子查询中是否存在满足条件的行。
- 如果在子查询中不存在满足条件的行:
- 条件返回 FALSE
- 继续在子查询中查找
- 如果在子查询中存在满足条件的行:
- 不在子查询中继续查找
- 条件返回 TRUE
- NOT EXISTS关键字表示如果不存在某种条件,则返回TRUE,否则返回FALSE。
题目:查询公司管理者的employee_id,last_name
SELECT employee_id, last_name FROM employees e1
WHERE EXISTS ( SELECT * FROM employees e2 WHERE e2.manager_id = e1.employee_id);
5.自连接和子查询
- 自连接速度比子查询快
子查询相当于对未知表进行查询后的条件判断, 而自连接是对自身已知数据的条件判断。