-- 多条件 SELECT last_name, salary, job_id FROM employees WHERE job_id = (SELECT job_id FROM employees WHERE employee_id =103) AND salary < (SELECT salary FROM employees WHERE employee_id =100);
SELECT last_name, salary FROM employees WHERE salary = (SELECTMIN(salary) FROM employees);
2.2 HAVING 中的子查询
子查询优先执行,得到子查询的结果后返回给主句的 WHERE 或 HAVING 充当过滤条件的一部分。
例如:查询最低工资大于部门 department_id = 50 的最低工资的部门
1 2 3 4 5 6 7 8
SELECT department_id, MIN(salary) FROM employees WHERE department_id ISNOT NULL GROUPBY department_id HAVINGMIN(salary) > (SELECTMIN(salary) FROM employees WHERE department_id =50);
SELECT employee_id, last_name, CASE department_id WHEN (SELECT department_id FROM departments WHERE location_id =1800) THEN'Canada' ELSE'USA'END location FROM employees;
-- 1. 不成对比较,逐个增加条件 SELECT employee_id, manager_id, department_id FROM employees WHERE manager_id IN (SELECT manager_id FROM employees WHERE employee_id IN (174, 141)) AND department_id IN (SELECT department_id FROM employees WHERE employee_id IN (174, 141)) AND employee_id NOTIN (174, 141);
1 2 3 4 5 6 7 8
-- 2. 当作一个集合进行比较 SELECT employee_id, manager_id, department_id FROM employees WHERE (manager_id, department_id) IN (SELECT manager_id, department_id FROM employees WHERE employee_id IN (141, 174)) AND employee_id NOTIN (141, 174);
【补充】可以查看一下具体的条件
1 2 3
SELECT manager_id, department_id FROM employees WHERE employee_id IN (141, 174);
3.2 常见多行比较操作符
操作符
含义
IN
等于列表中任意一个即可
ANY
和子查询返回的某个值比较
ALL
和子查询返回的所有值比较
SOME
和 ANY 相同
3.3 示例
3.3.1 ANY 和 ALL
ANY :返回其 job_id 中比 job_id 为 IT_PROG 部门任一工资低的员工信息
1 2 3 4 5 6 7 8
SELECT e.last_name, e.salary, e.job_id FROM employees e WHERE salary <ANY (SELECT e.salary FROM employees e WHERE e.job_id ='IT_PROG') AND e.job_id !='IT_PROG' ORDERBY e.salary DESC;
SELECT e.last_name, e.salary, e.job_id FROM employees e WHERE salary <ALL (SELECT e.salary FROM employees e WHERE e.job_id ='IT_PROG') AND e.job_id !='IT_PROG' ORDERBY e.salary DESC;
-- condition SELECT e.salary FROM employees e WHERE e.job_id ='IT_PROG';
最大为 9000 ,最小为 4200 :在使用 ANY 时,小于 9000 即可;但在使用 ALL 时,却需要小于 4200 。这就是二者明显的不同。
3.3.2 FROM 后嵌套查询分组语句
查询平均工资最低的部门 id
1 2 3 4 5 6 7 8
-- 法 1: 直接使用 MIN SELECT department_id FROM employees GROUPBY department_id HAVINGAVG(salary) = (SELECTMIN(avg_sal) FROM (SELECTAVG(salary) avg_sal FROM employees GROUPBY department_id) dept_avg_sal);
1 2 3 4 5 6 7
-- 法 2: 使用 ALL 间接表达最小 SELECT department_id FROM employees GROUPBY department_id HAVINGAVG(salary) <=ALL (SELECTAVG(salary) avg_sal FROM employees GROUPBY department_id);
GROUP BY 和单行函数联合使用,返回多行结果
4 相关子查询
4.1 相关子查询的例子
例如:查询员工信息,筛选条件为其工资要大于他所在部门的平均工资。
1 2 3 4 5 6 7
SELECT e.last_name, e.salary, e.department_id FROM employees e WHERE salary > (SELECTAVG(salary) FROM employees WHERE department_id = e.department_id) ORDERBY salary DESC;
如此,每次查一行数据时,就会执行子查询计算 department_id 等于当前行的平均工资,再返回给 WHERE 子句进行判断,决定是否查询这一行。
4.2 FROM 后使用子查询
同样是上面的例子
1 2 3 4 5 6 7 8
SELECT last_name, salary, e1.department_id FROM employees e1, (SELECT department_id, AVG(salary) dept_avg_sal FROM employees GROUPBY department_id) e2 WHERE e1.department_id = e2.department_id AND e1.salary > e2.dept_avg_sal ORDERBY salary DESC;
FROM 后使用子查询,相当于创造了一张虚拟表,一定要使用 () 和别名。
4.3 ORDER BY 后使用子查询
1 2 3 4 5
SELECT employee_id, salary FROM employees e ORDERBY (SELECT d.department_name FROM departments d WHERE e.department_id = d.department_id);
4.4 EXISTS 与 NOT EXISTS
EXISTS :检查在子查询中是否存在满足条件的行。逐行查询时:
如果在子查询中不存在满足条件的行:条件返回 FALSE 。继续在子查询中查找
如果在子查询中存在满足条件的行:条件返回 TRUE 。不在子查询中继续查找
NOT EXISTS 则相反。
例如:返回是公司管理者,即查找是否有 manager_id 等于这个员工的 employee.id
【方法一】EXISTS
1 2 3 4 5 6
SELECT employee_id, last_name FROM employees e1 WHEREEXISTS (SELECT* FROM employees e2 WHERE e2.manager_id = e1.employee_id);
注意:EXISTS 返回的是 True 和 False
【方法二】自连接
或者使用自连接,即创造一个虚拟表
1 2 3 4
SELECTDISTINCT e1.employee_id, e1.last_name FROM employees e1 JOIN employees e2 WHERE e1.employee_id = e2.manager_id;
【推荐】:相比子查询,自连接更为高效
【方法三】多行子查询
1 2 3 4 5
SELECT employee_id, last_name FROM employees WHERE employee_id IN (SELECTDISTINCT manager_id FROM employees);
4.5 相关子查询去更新与更新
4.5.1 相关更新
使用相关子查询依据一个表中的数据更新另一个表的数据。
先增加一个字段
1 2
ALTER TABLE employees ADD(department_name VARCHAR(50));