select 查询之子查询


文章目录

  • MySQL讲义第 30 讲——select 查询之子查询
  • 一、标量子查询
  • 1、查询高于所有员工平均工资的员工信息
  • 2、查询工资比王涛的工资还低的员工信息
  • 3、查询工资最高的员工信息
  • 二、列子查询
  • 1、查询比财务部所有员工的工资都高的员工的信息
  • 2、查询比财务部任意一个员工的工资高的员工的信息
  • 三、表子查询
  • 四、exists 子查询
  • 1、查询有学生的系的信息
  • 2、查询没有学生的系的信息


在一个 select 语句中嵌入另外一个 select 语句,被嵌入的 select 语句称之为子查询。子查询要么充当条件,要么充当主查询的数据源。根据子查询返回的结果可以把子查询分为以下几类:
(1)标量子查询:子查询结果是一个数据(单行单列)。
(2)列子查询:子查询结果是一列(多行单列)。
(3)表子查询:子查询结果是一张临时表(多行多列)。
(4)exists 子查询:根据子查询是否有返回值决定主查询的返回结果。

一、标量子查询

标量子查询的结果是一个数据(单行单列)。一般和 =、>、<、>=、<=、!= 等操作符一起使用来构造主查询的条件。针对下面的员工(emp)表进行查询。

mysql> select * from emp;
+------+-----------+--------+---------+--------+-----------+
| e_id | e_name    | gender | salary  | leader | dept_name |
+------+-----------+--------+---------+--------+-----------+
| 1101 | 张美华    | 女     | 5000.00 |   1104 | 销售部    |
| 1102 | 王涛      | 男     | 5200.00 |   1104 | 销售部    |
| 1103 | 张学有    | 男     | 4700.00 |   1104 | 销售部    |
| 1104 | 刘得华    | 男     | 5200.00 |   1104 | 销售部    |
| 1105 | 董雯花    | 女     | 5900.00 |   1104 | 销售部    |
| 1106 | 宋族营    | 男     | 6500.00 |   1104 | 销售部    |
| 2201 | 李霜江    | 男     | 7200.00 |   2202 | 财务部    |
| 2202 | 梁美丽    | 女     | 6400.00 |   2202 | 财务部    |
| 2203 | 王大强    | 男     | 6100.00 |   2202 | 财务部    |
| 3301 | 张美华    | 女     | 7800.00 |   3302 | 技术部    |
| 3302 | 赵紫龙    | 男     | 6900.00 |   3302 | 技术部    |
| 3303 | 诸葛量    | 男     | 9200.00 |   3302 | 技术部    |
| 3304 | 曹梦德    | 男     | 8400.00 |   3302 | 技术部    |
+------+-----------+--------+---------+--------+-----------+
13 rows in set (0.00 sec)

1、查询高于所有员工平均工资的员工信息

mysql> SELECT
    -> *
    -> FROM
    -> emp
    -> WHERE
    -> salary > 
    -> (SELECT avg(salary) FROM emp);
+------+-----------+--------+---------+--------+-----------+
| e_id | e_name    | gender | salary  | leader | dept_name |
+------+-----------+--------+---------+--------+-----------+
| 2201 | 李霜江    | 男     | 7200.00 |   2202 | 财务部    |
| 3301 | 张美华    | 女     | 7800.00 |   3302 | 技术部    |
| 3302 | 赵紫龙    | 男     | 6900.00 |   3302 | 技术部    |
| 3303 | 诸葛量    | 男     | 9200.00 |   3302 | 技术部    |
| 3304 | 曹梦德    | 男     | 8400.00 |   3302 | 技术部    |
+------+-----------+--------+---------+--------+-----------+
5 rows in set (0.02 sec)

2、查询工资比王涛的工资还低的员工信息

mysql> SELECT 
    -> *
    -> FROM 
    -> emp
    -> WHERE
    -> salary < 
    -> (SELECT salary FROM emp WHERE e_name = '王涛');
+------+-----------+--------+---------+--------+-----------+
| e_id | e_name    | gender | salary  | leader | dept_name |
+------+-----------+--------+---------+--------+-----------+
| 1101 | 张美华    | 女     | 5000.00 |   1104 | 销售部    |
| 1103 | 张学有    | 男     | 4700.00 |   1104 | 销售部    |
+------+-----------+--------+---------+--------+-----------+
2 rows in set (0.00 sec)

3、查询工资最高的员工信息

mysql> SELECT
    -> *
    -> FROM 
    -> emp
    -> WHERE 
    -> salary = 
    -> (SELECT min(salary) FROM emp);
+------+-----------+--------+---------+--------+-----------+
| e_id | e_name    | gender | salary  | leader | dept_name |
+------+-----------+--------+---------+--------+-----------+
| 1103 | 张学有    | 男     | 4700.00 |   1104 | 销售部    |
+------+-----------+--------+---------+--------+-----------+
1 row in set (0.02 sec)

二、列子查询

列子查询的结果是一列(多行单列),可以看成一个集合。一般搭配和 IN、ANY | SOME、ALL 等操作符一起使用。例如:

1、查询比财务部所有员工的工资都高的员工的信息

mysql> SELECT
    -> *
    -> FROM 
    -> emp
    -> WHERE
    -> salary > ALL
    -> (SELECT salary FROM emp WHERE dept_name = '财务部');
+------+-----------+--------+---------+--------+-----------+
| e_id | e_name    | gender | salary  | leader | dept_name |
+------+-----------+--------+---------+--------+-----------+
| 3301 | 张美华    | 女     | 7800.00 |   3302 | 技术部    |
| 3303 | 诸葛量    | 男     | 9200.00 |   3302 | 技术部    |
| 3304 | 曹梦德    | 男     | 8400.00 |   3302 | 技术部    |
+------+-----------+--------+---------+--------+-----------+
3 rows in set (0.02 sec)

--说明:以上查询等价于:
mysql> SELECT
    -> *
    -> FROM 
    -> emp
    -> WHERE
    -> salary > 
    -> (SELECT max(salary) FROM emp WHERE dept_name = '财务部');
+------+-----------+--------+---------+--------+-----------+
| e_id | e_name    | gender | salary  | leader | dept_name |
+------+-----------+--------+---------+--------+-----------+
| 3301 | 张美华    | 女     | 7800.00 |   3302 | 技术部    |
| 3303 | 诸葛量    | 男     | 9200.00 |   3302 | 技术部    |
| 3304 | 曹梦德    | 男     | 8400.00 |   3302 | 技术部    |
+------+-----------+--------+---------+--------+-----------+
3 rows in set (0.02 sec)

2、查询比财务部任意一个员工的工资高的员工的信息

mysql> SELECT
    -> *
    -> FROM 
    -> emp
    -> WHERE
    -> salary > ANY
    -> (SELECT salary FROM emp WHERE dept_name = '财务部');
+------+-----------+--------+---------+--------+-----------+
| e_id | e_name    | gender | salary  | leader | dept_name |
+------+-----------+--------+---------+--------+-----------+
| 1106 | 宋族营    | 男     | 6500.00 |   1104 | 销售部    |
| 2201 | 李霜江    | 男     | 7200.00 |   2202 | 财务部    |
| 2202 | 梁美丽    | 女     | 6400.00 |   2202 | 财务部    |
| 3301 | 张美华    | 女     | 7800.00 |   3302 | 技术部    |
| 3302 | 赵紫龙    | 男     | 6900.00 |   3302 | 技术部    |
| 3303 | 诸葛量    | 男     | 9200.00 |   3302 | 技术部    |
| 3304 | 曹梦德    | 男     | 8400.00 |   3302 | 技术部    |
+------+-----------+--------+---------+--------+-----------+
7 rows in set (0.00 sec)

--说明:以上查询等价于:
mysql> SELECT
    -> *
    -> FROM 
    -> emp
    -> WHERE
    -> salary > 
    -> (SELECT min(salary) FROM emp WHERE dept_name = '财务部');
+------+-----------+--------+---------+--------+-----------+
| e_id | e_name    | gender | salary  | leader | dept_name |
+------+-----------+--------+---------+--------+-----------+
| 1106 | 宋族营    | 男     | 6500.00 |   1104 | 销售部    |
| 2201 | 李霜江    | 男     | 7200.00 |   2202 | 财务部    |
| 2202 | 梁美丽    | 女     | 6400.00 |   2202 | 财务部    |
| 3301 | 张美华    | 女     | 7800.00 |   3302 | 技术部    |
| 3302 | 赵紫龙    | 男     | 6900.00 |   3302 | 技术部    |
| 3303 | 诸葛量    | 男     | 9200.00 |   3302 | 技术部    |
| 3304 | 曹梦德    | 男     | 8400.00 |   3302 | 技术部    |
+------+-----------+--------+---------+--------+-----------+
7 rows in set (0.00 sec)

三、表子查询

表子查询结果是一张临时表(多行多列),一般作为主查询的数据源。例如:查询比本部门平均工资高的员工的信息。

mysql> SELECT
    -> e.*,
    -> d.salary_avg
    -> FROM 
    -> emp e JOIN (SELECT dept_name,avg(salary) salary_avg FROM emp GROUP BY dept_name) d 
    -> ON e.dept_name = d.dept_name
    -> WHERE
    -> e.salary > d.salary_avg;
+------+-----------+--------+---------+--------+-----------+-------------+
| e_id | e_name    | gender | salary  | leader | dept_name | salary_avg  |
+------+-----------+--------+---------+--------+-----------+-------------+
| 1105 | 董雯花    | 女     | 5900.00 |   1104 | 销售部    | 5416.666667 |
| 1106 | 宋族营    | 男     | 6500.00 |   1104 | 销售部    | 5416.666667 |
| 2201 | 李霜江    | 男     | 7200.00 |   2202 | 财务部    | 6566.666667 |
| 3303 | 诸葛量    | 男     | 9200.00 |   3302 | 技术部    | 8075.000000 |
| 3304 | 曹梦德    | 男     | 8400.00 |   3302 | 技术部    | 8075.000000 |
+------+-----------+--------+---------+--------+-----------+-------------+
5 rows in set (0.00 sec)

四、exists 子查询

根据子查询是否有返回值决定主查询的返回结果。例如有以下两张表:

mysql> select * from dept;
+---------+--------------+
| dept_id | dept_name    |
+---------+--------------+
| D01     | 管理系       |
| D02     | 计算机系     |
| D03     | 数学系       |
| D04     | 法律系       |
| D05     | 艺术系       |
+---------+--------------+
5 rows in set (0.00 sec)

mysql> select * from stu;
+-----------+-----------+--------+---------------------+--------+-------------+---------+
| stu_id    | stu_name  | gender | birth               | height | phone       | dept_id |
+-----------+-----------+--------+---------------------+--------+-------------+---------+
| 201801101 | 王占峰    | 男     | 1999-12-30 00:00:00 |  177.0 | 15937320987 | D02     |
| 201801102 | 刘国强    | 男     | 2000-08-14 00:00:00 |  174.0 | 15937320789 | D02     |
| 201801103 | 巩莉      | 女     | 2000-06-18 00:00:00 |  170.0 | 15937320456 | D02     |
| 201801104 | 宋丹风    | 女     | 1999-11-20 00:00:00 |  165.0 | 15937320444 | D02     |
| 201801201 | 王艳艳    | 女     | 1999-09-30 00:00:00 |  162.0 | NULL        | NULL    |
| 201801202 | 赵牡丹    | 女     | 2001-08-10 00:00:00 |  160.0 | 15937320666 | D03     |
| 201801203 | 王鹏飞    | 男     | 2000-10-19 00:00:00 |  174.0 | 15937320555 | D03     |
| 201901002 | 王宏伟    | 男     | 2001-02-15 00:00:00 |  180.0 | 15937320255 | D01     |
| 201901003 | 张静静    | 女     | 2001-08-17 00:00:00 |  167.0 | 15937320123 | D01     |
| 201901004 | 李刚      | 男     | 2000-12-25 00:00:00 |  178.0 | 15937320321 | D01     |
| 201901005 | 刘鹏      | 男     | 2001-12-18 00:00:00 |  176.0 | NULL        | D01     |
+-----------+-----------+--------+---------------------+--------+-------------+---------+
11 rows in set (0.00 sec)

1、查询有学生的系的信息

mysql> SELECT
    -> *
    -> FROM
    -> dept
    -> WHERE
    -> exists (SELECT * FROM stu WHERE dept_id = dept.dept_id);
+---------+--------------+
| dept_id | dept_name    |
+---------+--------------+
| D01     | 管理系       |
| D02     | 计算机系     |
| D03     | 数学系       |
+---------+--------------+
3 rows in set (0.00 sec)
--说明:把每一个系的系编号带入学生表,只要查询到一条记录,就表示该系有学生。

2、查询没有学生的系的信息

mysql> SELECT
    -> *
    -> FROM
    -> dept
    -> WHERE
    -> not exists (SELECT * FROM stu WHERE dept_id = dept.dept_id);
+---------+-----------+
| dept_id | dept_name |
+---------+-----------+
| D04     | 法律系    |
| D05     | 艺术系    |
+---------+-----------+
2 rows in set (0.00 sec)