MySQL 子查询

发布于:2025-08-11 ⋅ 阅读:(14) ⋅ 点赞:(0)

子查询指一个查询语句嵌套在另一个查询语句内部的查询这个特性从MySQL 4.1开始引入

 单行子查询

#4.1 单行操作符: =  !=  >   >=  <  <=

引入

#1. 由一个具体的需求,引入子查询
#需求:谁的工资比Abel的高?
#方式1:
SELECT salary
FROM employees
WHERE last_name = 'Abel';

SELECT last_name,salary
FROM employees
WHERE salary > 11000;

#方式2:自连接
SELECT e2.last_name,e2.salary
FROM employees e1,employees e2
WHERE e2.`salary` > e1.`salary` #多表的连接条件
AND e1.last_name = 'Abel';

#方式3:子查询
SELECT last_name,salary
FROM employees
WHERE salary > (
		SELECT salary
		FROM employees
		WHERE last_name = 'Abel'
		);

称谓规范

#2. 称谓的规范:外查询(或主查询)、内查询(或子查询)

/*
- 子查询(内查询)在主查询之前一次执行完成。
- 子查询的结果被主查询(外查询)使用 。
- 注意事项
  - 子查询要包含在括号内
  - 将子查询放在比较条件的右侧
  - 单行操作符对应单行子查询,多行操作符对应多行子查询

*/

独立条件子查询  && 行比较 

#题目:查询与141号员工的manager_id和department_id相同的其他员工
#的employee_id,manager_id,department_id。
#方式1:
SELECT employee_id,manager_id,department_id
FROM employees
WHERE manager_id = (
		    SELECT manager_id
		    FROM employees
		    WHERE employee_id = 141
		   )
AND department_id = (
		    SELECT department_id
		    FROM employees
		    WHERE employee_id = 141
		   )
AND employee_id <> 141;

#方式2:了解
SELECT employee_id,manager_id,department_id
FROM employees
WHERE (manager_id,department_id) = (
				    SELECT manager_id,department_id
			            FROM employees
				    WHERE employee_id = 141
				   )
AND employee_id <> 141;

CASE 表达式详解

CASE表达式是 SQL 中用于进行条件判断的工具,类似编程语言中的if-else语句。

CASE 被判断的列
  WHEN 条件值1 THEN 结果1
  WHEN 条件值2 THEN 结果2
  ...
  ELSE 默认结果
END 列别名

#题目:显式员工的employee_id,last_name和location。        ( location 需要计算得出)

#其中,若员工department_id与location_id为1800的department_id相同,
#则location为’Canada’,其余则为’USA’。



SELECT 
    employee_id,
    last_name,
    CASE 
        WHEN department_id = (SELECT department_id FROM departments WHERE location_id = 1800) 
        THEN 'Canada'
        ELSE 'USA' 
    END "location"
FROM 
    employees;

子查询空值问题

  • 空值产生:表无匹配 last_name = 'Haas' 员工时,子查询返回空集,主查询条件等价于 job_id = NULL 。
  • NULL 特性NULL 代表未知值,用 =!= 等比较,结果为 “未知(UNKNOWN)” ,使主查询条件不成立,返回空结果,即便表有 job_id 为 NULL 的员工也选不出。
  • 解决办法:用 IN 替代 = 处理子查询可能无结果的情况,逻辑更合理,也可结合 IS NULL 显式处理含 NULL 的场景 。

多行子查询

多行子查询的操作符:

IN  ANY ALL SOME(同ANY)

IN  ANY ALL SOME(同ANY)

 非法使用子查询

#4.3 非法使用子查询
#错误:Subquery returns more than 1 row
SELECT employee_id, last_name
FROM   employees
WHERE  salary =
                (SELECT   MIN(salary)
                 FROM     employees
                 GROUP BY department_id);         

#5.多行子查询
#5.1 多行子查询的操作符: IN  ANY ALL SOME(同ANY)

#5.2举例:
# IN:
SELECT employee_id, last_name
FROM   employees
WHERE  salary IN
                (SELECT   MIN(salary)
                 FROM     employees
                 GROUP BY department_id); 
                 

#	题目:返回其它job_id中比job_id为‘IT_PROG’部门任一工资低的员工的员工号、
# 姓名、job_id 以及salary

SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE job_id <> 'IT_PROG'
AND salary < ANY (
		SELECT salary
		FROM employees
		WHERE job_id = 'IT_PROG'
		);
#题目:返回其它job_id中比job_id为‘IT_PROG’部门所有工资低的员工的员工号、
#姓名、job_id 以及salary

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

重点题目

#题目:查询平均工资最低的部门id
#MySQL中聚合函数是不能嵌套使用的。


#方式1:
SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary) = (
			SELECT MIN(avg_sal)
			FROM(
				SELECT AVG(salary) avg_sal
				FROM employees
				GROUP BY department_id
				) t_dept_avg_sal           子查询,表要起别名
			);


#方式2:
SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary) <= ALL(	
			SELECT AVG(salary) avg_sal
			FROM employees
			GROUP BY department_id
			) 

子查询存在NULL值

  • 子查询含 NULL + 主查询用 IN
    仅匹配子查询中的非 NULL 值,NULL 会被忽略,结果正常(只返回主查询字段在子查询非 NULL 集合中的记录)。

  • 子查询含 NULL + 主查询用 NOT IN
    结果必为空集(因 x != NULL 结果为 UNKNOWN,导致整体条件失效)。

    • NOT IN 等价于 “值不等于子查询中的所有值”(即 x != a AND x != b AND ...)。
    • 若子查询含 NULL,则条件中会包含 x != NULL,而其结果为 UNKNOWN
    • 由于 AND 逻辑中只要有一个 UNKNOWN,整体结果就为 UNKNOWN(MySQL 视为 FALSE),因此主查询返回空集
  • 建议:子查询可能有 NULL 时,避免用 NOT IN,改用 NOT EXISTS。

相关子查询