MySQL子查询
子查询概述
子查询指一个查询语句嵌套在另一个查询语句内部的查询。
子查询的基本语法结构
SELECT 字段名
FROM 表名
WHERE 字段名1 = (
SELECT 字段名1
FROM 表名
WHERE 过滤条件);
- 子查询(内查询)在主查询之前一次执行完成,子查询的结果被主查询(外查询)使用
- 子查询要包含在括号内,建议将子查询放在比较条件的右侧单行操作符对应单行子查询,多行操作符对应多行子查询
SELECT last_name,salary FROM employees WHERE salary > ( SELECT salary FROM employees WHERE last_name = 'suolong' );
单行子查询
-
单行比较操作符
-- 查询与141号或174号员工的manager_id和department_id相同的其它员工的employee_id,manager_id,department_id SELECT employee_id,manager_id,department_id FROM employees WHERE manager_id = ( SELECT manager_id FROM employees WHERE employee_id = 141) AND ( 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; -
HAVING 中的子查询
SELECT 字段名1, 分组函数(字段名) FROM 表名 GROUP BY 字段名1 HAVING 分组函数1(字段名) = ( SELECT 分组函数1(字段名) FROM 表名 WHERE 过滤条件); -- 首先执行子查询。 -- 向主查询中的 HAVING 子句返回结果。-- 查询最低工资大于118号部门最低工资的部门id和其最低工资 SELECT department_id,MIN(salary) FROM employees GROUP BY department_id HAVING MIN(salary) > ( SELECT MIN(salary) FROM employees WHERE department_id = 118 ); -
CASE中的子查询
SELECT 字段名 CASE WHEN ( SELECT 字段名1 FROM 表名 WHERE 过滤条件) THEN 结果1 ELSE 结果2 END AS 别名 FROM 表名;-- 显示员工的employee_id,last_name和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 d JOIN locations l ON d.location_id = l.location_id WHERE l.location_id = 1800 ) THEN 'Canada' ELSE 'USA' END AS "location" FROM employees;
多行子查询
-
多行子查询的基本语法结构
SELECT 字段名 FROM 表名 WHERE 字段名1 IN ( SELECT 字段名1 FROM 表名 WHERE 过滤条件); -- 也称为集合比较子查询,内查询返回多行,使用多行比较操作符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 salary < ALL( SELECT salary FROM employees WHERE job_id = 'IT_PROG') AND job_id <> 'IT_PROG'; -- 方式2 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'; -- 查新平均工资最低的部门id SELECT department_id FROM employees GROUP BY department_id HAVING AVG(salary) = ( SELECT MIN(avg_sal) FROM ( SELECT AVG(salary) AS "avg_sal" FROM employees GROUP BY department_id ) AS t_dept_avg_sal ); -- 方式2 SELECT department_id FROM employees GROUP BY department_id HAVING AVG(salary) <= ALL( SELECT AVG(salary) FROM employees GROUP BY department_id ); -- 方式3 SELECT department_id FROM employees GROUP BY department_id ORDER BY AVG(salary) ASC LIMIT 1;
相关子查询
-
相关子查询的基本语法结构
- 如果子查询的执行依赖于外部查询,通常情况下都是因为子查询中的表用到了外部的表,并进行了条件关联,因此每执行一次外部查询,子查询都要重新计算一次,这样的子查询就称之为关联子查询。相关子查询按照一行接一行的顺序执行,主查询的每一行都执行一次子查询。
-- 查询员工中工资大于本部门平均工资的员工的last_name,salary和其department_id -- 方式1:相关子查询 SELECT last_name,salary,department_id FROM employees e1 WHERE salary > ( SELECT AVG(salary) FROM employees e2 WHERE department_id = e1.department_id ); -- 方式2:FROM中声明子查询 SELECT e.last_name,e.salary,e.department_id FROM employees e,( SELECT department_id,AVG(salary) AS "avg_sal" FROM employees GROUP BY department_id ) AS t_dept_avg_sal WHERE e.department_id = t_dept_avg_sal.department_id AND e.salary > t_dept_avg_sal.avg_sal;
EXISTS 与 NOT EXISTS关键字
- 关联子查询通常也会和 EXISTS操作符一起来使用,用来检查在子查询中是否存在满足条件的行
- 如果在子查询中不存在满足条件的行,条件返回 FALSE,继续在子查询中查找
- 如果在子查询中存在满足条件的行,不在子查询中继续查找条件返回 TRUE
- NOT EXISTS关键字表示如果不存在某种条件,则返回TRUE,否则返回FALSE
-- 查询公司管理者的employee_id,last_name,job_id,department_id信息 -- 方式1:自连接 SELECT DISTINCT mgr.employee_id,mgr.last_name,mgr.job_id,mgr.department_iFROM employees emp JOIN employees mgr ON emp.manager_id = mgr.employee_id; -- 方式2:子查询 SELECT employee_id,last_name,job_id,department_id FROM employees WHERE employee_id IN ( SELECT DISTINCT manager_id FROM employees ); -- 方式3:EXISTS SELECT employee_id,last_name,job_id,department_id FROM employees e1 WHERE EXISTS ( SELECT * FROM employees e2 WHERE e1.employee_id = e2.manager_id );-- 查询departments表中,不存在与employees表中的部门的department_id和department_name -- 方式1 SELECT d.department_id,department_name FROM employees e RIGHT JOIN departments d ON d.department_id = e.department_id WHERE e.department_id IS NULL; -- 方式2 SELECT department_id,department_name FROM departments d WHERE NOT EXISTS ( SELECT * FROM employees e WHERE d.department_id = e.department_id );
子查询的编写技巧
如果子查询相对较简单,建议从外往内写。一旦子查询结构较复杂,则建议从里往外写
如果是相关子查询的话,通常都是从外往里写