飞道的博客

MySQL基本操作整理(五)、子查询

454人阅读  评论(0)

本文整理MySQL中的子查询,相比于其他的分组查询、排序查询和连接查询等,子查询略微复杂。本文按照子查询出现的位置,将子查询分为主要的几类,并以实际的案例进行介绍,以求用形象的语言来表达清楚子查询。

一、子查询介绍

含义

出现在其他语句中的select语句,称为子查询或内查询(其他语句可以是增删改等);外部的查询语句,称为主查询或外查询。

分类

1.按子查询出现的位置分类:

  • select后:仅仅支持标量子查询
  • from后:支持表子查询
  • where或having后:支持标量子查询(单行子查询)、列子查询(多行子查询)以及行子查询
  • exists后(称为相关子查询)

2.按结果了集的行列数分类,分为如下几类:

  • 标量子查询(结果集只有一行一列)
  • 列子查询(结果集只有一列多行)
  • 行子查询(结果集有一行多列)
  • 表子查询(结果集一般为多行多列)

重点为:位于where或者having后面的标量子查询与列子查询

二、WHERE或HAVING后的子查询

1. 标量子查询

将查询结果作为标量使用:
案例1:查询员工表中工资比 Abel高的员工信息

SELECT *
FROM employees
WHERE salary > (
	SELECT salary
	FROM employees
	WHERE last_name = 'Abel'
);

查询时可以添加多个子查询作为筛选条件:
案例2:查询员工表中,job_id与141号员工相同,salary比143号员工高的员工的姓名,job_id 和工资

SELECT last_name,job_id,salary
FROM employees
WHERE job_id = (
	SELECT job_id
	FROM employees
	WHERE employee_id = 141
) AND salary>(
	SELECT salary
	FROM employees
	WHERE employee_id = 143
);

案例3:查询最低工资大于50号部门最低工资的部门id和其最低工资

#初步实现可以分三步走:
#(1)查询50号部门的最低工资
SELECT  MIN(salary)
FROM employees
WHERE department_id = 50

#(2)查询每个部门的最低工资
SELECT MIN(salary),department_id
FROM employees
GROUP BY department_id

#(3)在(2)基础上筛选,满足min(salary)>(1)
SELECT MIN(salary),department_id
FROM employees
GROUP BY department_id
HAVING MIN(salary)>(
	SELECT  MIN(salary)
	FROM employees
	WHERE department_id = 50
);

2. 列子查询

案例1:返回location_id是1400或1700的部门中的所有员工姓名

#(1)查询location_id是1400或1700的部门编号
SELECT DISTINCT department_id
FROM departments
WHERE location_id IN(1400,1700)

#(2)查询员工姓名,要求部门号是(1)列表中的某一个
SELECT last_name
FROM employees
WHERE department_id IN(
	SELECT DISTINCT department_id
	FROM departments
	WHERE location_id IN(1400,1700)
);

案例2:返回其它工种中比job_id为‘IT_PROG’工种任一工资低的员工的员工号、姓名、job_id 以及salary
分析:比任一工资低的,那么只要低于最大的就行了。如a < any(10, 20, 30)等价于 a < max(10, 20, 30)

SELECT employee_id, last_name, job_id, salary
FROM employees
WHERE salary < (
	SELECT MAX(salary)
	FROM employees
	WHERE job_id = 'IT_PROG'
)AND job_id<>'IT_PROG';

或者

SELECT last_name,employee_id,job_id,salary
FROM employees
WHERE salary<ANY(
	SELECT DISTINCT salary
	FROM employees
	WHERE job_id = 'IT_PROG'

) AND job_id<>'IT_PROG';

案例3:返回其它工种中比job_id为‘IT_PROG’工种所有工资都低的员工 的员工号、姓名、job_id 以及salary

SELECT employee_id, last_name, job_id, salary
FROM employees 
WHERE salary < (
     SELECT MIN(salary)
     FROM employees
     WHERE job_id = 'IT_PROG'
) AND job_id <> 'IT_PROG';

或者

SELECT last_name,employee_id,job_id,salary
FROM employees
WHERE salary<ALL(
	SELECT DISTINCT salary
	FROM employees
	WHERE job_id = 'IT_PROG'

) AND job_id<>'IT_PROG';

3. 行子查询(了解)

行子查询的结果集为一行多列或多行多列
案例:查询员工编号最小并且工资最高的员工信息

一般做法:
SELECT *
FROM employees
WHERE employee_id=(
	SELECT MIN(employee_id)
	FROM employees
)AND salary=(
	SELECT MAX(salary)
	FROM employees
);

行子查询:
SELECT * 
FROM employees
WHERE (employee_id,salary)=(
	SELECT MIN(employee_id),MAX(salary) #结果集为一行多列
	FROM employees
);

三、SELECT后的子查询

说明:select后的子查询仅仅支持标量子查询

案例:查询每个部门的员工个数
效果如下图,前面为departments表的信息,而departments表中必定有些部门在employees表中没有员工与其对应,则个数为0,如下半部分。

#分两步分析:
#(1)如下效果为每个部门的个数都是总员工数
SELECT d.*,(
	SELECT COUNT(*)
	FROM employees e
 ) 个数
FROM departments d;
#(2)筛选条件为员工表的部门id等于部门表的部门id
SELECT d.*,(
	SELECT COUNT(*)
	FROM employees e
	WHERE e.department_id = d.`department_id`
 ) 个数
 FROM departments d;

四、FROM后的子查询

说明:将子查询结果充当一张表,要求必须起别名,否则找不到
案例:查询每个部门的平均工资的工资等级

分析:(1)查询每个部门的平均工资
SELECT AVG(salary),department_id
FROM employees
GROUP BY department_id
#查询工资等级表
SELECT * FROM job_grades;2) 连接(1)的结果集和job_grades表,筛选条件为平均工资 between lowest_sal and highest_sal
SELECT  ag_dep.*,g.`grade_level`
FROM (
	SELECT AVG(salary) ag,department_id
	FROM employees
	GROUP BY department_id
) ag_dep
INNER JOIN job_grades g
ON ag_dep.ag BETWEEN lowest_sal AND highest_sal;

五、exists后的子查询(相关子查询)

exists后的子查询也称为相关子查询。
语法为:exists (完整的查询语句)
结果:1或0

#举例:以下查询结果为 1
SELECT EXISTS(SELECT employee_id FROM employees);

案例1:查询有员工的部门名

分析:(1)查询部门表的所有部门id和部门名
SELECT d.`department_id`, department_name
FROM departments d

(2)在该结果集上筛选出有员工的(可以查询任意信息,因为只要判断是否存在即可)
SELECT d.`department_id`, department_name
FROM departments d
WHERE EXISTS(
	SELECT *
	FROM employees e
	WHERE d.`department_id`=e.`department_id` #子查询涉及到主查询的字段,所以称相关子查询
);

能用EXISTS的绝对可以用IN来实现:

SELECT department_name
FROM departments d
WHERE d.`department_id` IN(
	SELECT department_id
	FROM employees
);

案例2:查询没有女朋友的男神信息

# IN 方法:
SELECT bo.*
FROM boys bo
WHERE bo.id NOT IN(
	SELECT b.`boyfriend_id`
	FROM beauty b
);

# EXISTS 方法:
SELECT bo.*
FROM boys bo
WHERE NOT EXISTS (
	SELECT *
	FROM beauty b
	WHERE b.`boyfriend_id` = bo.`id`
);

转载:https://blog.csdn.net/shao_yc/article/details/106148760
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场