select 高级查询之子查询

2020-09-28 17:34:22 浏览数 (1)

1.1 概述

  在 SQL 语言中,一个 SELECT-FROM-WHERE 语句称为一个查询块。当获得一个查询的答案需要多个步骤的操作,首先必须创建一个查询来确定用户不知道但包含在数据库中的值,将一个查询块嵌套在另一个查询块的 WHERE 字句或 HAVING 短语的条件中查询块称为子查询或内层查询。外部的 SELECT 查询语句,称为主查询或外查询。按结果集的行列数不同子查询可以分为 4 种  ♞ 标量子查询(结果集只有一行一列)  ♞ 列子查询(结果集只有一列多行)  ♞ 行子查询(结果集有一行多列)  ♞ 表子查询(结果集一般为多行多列)

1.2 数据准备

代码语言:javascript复制
# 员工表
mysql> select * from emp;
 ------ -------- -------- ------ ------------ ---------- ---------- --------- 
| id   | ename  | job_id | mgr  | joindate   | salary   | bonus    | dept_id |
 ------ -------- -------- ------ ------------ ---------- ---------- --------- 
| 1001 | 孙悟空 |      4 | 1004 | 2000-12-17 | 8000.00  | NULL     |      20 |
| 1002 | 卢俊义 |      3 | 1006 | 2001-02-20 | 16000.00 | 3000.00  |      30 |
| 1003 | 林冲   |      3 | 1006 | 2001-02-22 | 12500.00 | 5000.00  |      30 |
| 1004 | 唐僧   |      2 | 1009 | 2001-04-02 | 29750.00 | NULL     |      20 |
| 1005 | 李逵   |      4 | 1006 | 2001-09-28 | 12500.00 | 14000.00 |      30 |
| 1006 | 宋江   |      2 | 1009 | 2001-05-01 | 28500.00 | NULL     |      30 |
| 1007 | 刘备   |      2 | 1009 | 2001-09-01 | 24500.00 | NULL     |      10 |
| 1008 | 猪八戒 |      4 | 1004 | 2007-04-19 | 30000.00 | NULL     |      20 |
| 1009 | 罗贯中 |      1 | NULL | 2001-11-17 | 50000.00 | NULL     |      10 |
| 1010 | 吴用   |      3 | 1006 | 2001-09-08 | 15000.00 | 0.00     |      30 |
| 1011 | 沙僧   |      4 | 1004 | 2007-05-23 | 11000.00 | NULL     |      20 |
| 1012 | 李逵   |      4 | 1006 | 2001-12-03 | 9500.00  | NULL     |      30 |
| 1013 | 小白龙 |      4 | 1004 | 2001-12-03 | 30000.00 | NULL     |      20 |
| 1014 | 关羽   |      4 | 1007 | 2002-01-23 | 13000.00 | NULL     |      10 |
 ------ -------- -------- ------ ------------ ---------- ---------- --------- 
14 rows in set (0.15 sec)

# 部门信息表
mysql> select * from dept;
 ---- -------- ------ 
| id | dname  | loc  |
 ---- -------- ------ 
| 10 | 教研部 | 北京 |
| 20 | 学工部 | 上海 |
| 30 | 销售部 | 广州 |
| 40 | 财务部 | 深圳 |
 ---- -------- ------ 
4 rows in set (0.15 sec)

# 工作职责表
mysql> select * from job;
 ---- -------- -------------------- 
| id | jname  | description        |
 ---- -------- -------------------- 
|  1 | 董事长 | 管理整个公司,接单 |
|  2 | 经理   | 管理部门员工       |
|  3 | 销售员 | 向客人推销产品     |
|  4 | 文员   | 使用办公软件       |
 ---- -------- -------------------- 
4 rows in set (0.16 sec)

# 薪资等级表
mysql> select * from salarygrade;
 ------- ---------- ---------- 
| grade | losalary | hisalary |
 ------- ---------- ---------- 
|     1 |     7000 |    12000 |
|     2 |    12010 |    14000 |
|     3 |    14010 |    20000 |
|     4 |    20010 |    30000 |
|     5 |    30010 |    99990 |
 ------- ---------- ---------- 
5 rows in set (0.14 sec)

1.3 select 后的子查询

1.3.1 查询每个部门员工个数

代码语言:javascript复制
mysql> select dept.*, 
	-> ( select count(*) from emp where emp.dept_id = dept.id ) as 员工个数
	-> from dept;
 ---- -------- ------ ---------- 
| id | dname  | loc  | 员工个数 |
 ---- -------- ------ ---------- 
| 10 | 教研部 | 北京 |        3 |
| 20 | 学工部 | 上海 |        5 |
| 30 | 销售部 | 广州 |        6 |
| 40 | 财务部 | 深圳 |        0 |
 ---- -------- ------ ---------- 
4 rows in set (2.02 sec)

1.3.2 查询 1002 号员工的姓名和部门名称

代码语言:javascript复制
mysql> select ename as 姓名, 
	-> (select dname from dept where emp.dept_id = dept.id) as 部门名 
	-> from emp 
	-> where id = 1002;
 -------- -------- 
| 姓名   | 部门名 |
 -------- -------- 
| 卢俊义 | 销售部 |
 -------- -------- 
1 row in set (0.15 sec)

1.4 from 后的子查询

1.4.1 查询每个部门的平均工资

代码语言:javascript复制
mysql> select avg(salary) as avg, dept_id from emp group by dept_id;
 -------------- --------- 
| avg          | dept_id |
 -------------- --------- 
| 29166.666667 |      10 |
| 21750.000000 |      20 |
| 15666.666667 |      30 |
 -------------- --------- 
3 rows in set (0.11 sec)


mysql> select dept.dname as 部门, t.avg as 平均工资 from 
	-> ( select avg(salary) as avg, dept_id from emp group by dept_id ) as t, dept 
	-> where t.dept_id = dept.id;
 -------- -------------- 
| 部门   | 平均工资     |
 -------- -------------- 
| 教研部 | 29166.666667 |
| 学工部 | 21750.000000 |
| 销售部 | 15666.666667 |
 -------- -------------- 
3 rows in set (0.18 sec)

1.5 where 后的子查询

1.5.1 查询工资高于 30 号部门平均工资的员工信息

代码语言:javascript复制
mysql> select avg(salary) from emp where dept_id = 30;
 -------------- 
| avg(salary)  |
 -------------- 
| 15666.666667 |
 -------------- 
1 row in set (0.10 sec)


mysql> select * from emp where ( select avg(salary) from emp where dept_id = 30 ) < salary;
 ------ -------- -------- ------ ------------ ---------- --------- --------- 
| id   | ename  | job_id | mgr  | joindate   | salary   | bonus   | dept_id |
 ------ -------- -------- ------ ------------ ---------- --------- --------- 
| 1002 | 卢俊义 |      3 | 1006 | 2001-02-20 | 16000.00 | 3000.00 |      30 |
| 1004 | 唐僧   |      2 | 1009 | 2001-04-02 | 29750.00 | NULL    |      20 |
| 1006 | 宋江   |      2 | 1009 | 2001-05-01 | 28500.00 | NULL    |      30 |
| 1007 | 刘备   |      2 | 1009 | 2001-09-01 | 24500.00 | NULL    |      10 |
| 1008 | 猪八戒 |      4 | 1004 | 2007-04-19 | 30000.00 | NULL    |      20 |
| 1009 | 罗贯中 |      1 | NULL | 2001-11-17 | 50000.00 | NULL    |      10 |
| 1013 | 小白龙 |      4 | 1004 | 2001-12-03 | 30000.00 | NULL    |      20 |
 ------ -------- -------- ------ ------------ ---------- --------- --------- 
7 rows in set (0.16 sec)

1.5.2 查询有工资高于 29000 的部门

代码语言:javascript复制
mysql> select dept_id from emp where salary > 29000 group by dept_id;
 --------- 
| dept_id |
 --------- 
|      10 |
|      20 |
 --------- 
2 rows in set (0.11 sec)


mysql> select dname as 部门名 
	-> from dept 
	-> where id in (select dept_id from emp where salary > 29000 group by dept_id);
 -------- 
| 部门名 |
 -------- 
| 学工部 |
| 教研部 |
 -------- 
2 rows in set (0.14 sec)

1.5.3 查询部门号最小,工资最高的员工信息

代码语言:javascript复制
mysql> select min(dept_id), max(salary) from emp;
 -------------- ------------- 
| min(dept_id) | max(salary) |
 -------------- ------------- 
|           10 | 50000.00    |
 -------------- ------------- 
1 row in set (0.11 sec)


mysql> select * from emp where (dept_id, salary) = (select min(dept_id), max(salary) from emp);
 ------ -------- -------- ------ ------------ ---------- ------- --------- 
| id   | ename  | job_id | mgr  | joindate   | salary   | bonus | dept_id |
 ------ -------- -------- ------ ------------ ---------- ------- --------- 
| 1009 | 罗贯中 |      1 | NULL | 2001-11-17 | 50000.00 | NULL  |      10 |
 ------ -------- -------- ------ ------------ ---------- ------- --------- 
1 row in set (19.54 sec)

1.6 注意

 ① 子查询放在小括号内,且一般放在条件的右侧。  ② 标量子查询,一般搭配着单行操作符使用,列子查询,一般搭配着多行操作符使用。  ③ 子查询的执行优先于主查询执行,因为主查询的条件用到了子查询的结果。  ④ select 后面的子查询,仅仅支持标量子查询,即结果集只有一行一列。  ⑤ from 后面的子查询是将子查询的结果集充当一张临时表,要求必须起别名,否者这个表找不到。然后将真实的表和子查询结果表进行连接查询。  ⑥ where 或 having 后面可以有:标量子查询、 列子查询(一般搭配着多行操作符使用 in、any、some、all 等)、行子查询。

0 人点赞