来一篇
MySQL-子查询
记录一下这个美好的时光,学习记录篇,下文中所有SQL 语句 均可在 MySQL DB 学习Demo
此处下载SQL语句执行,有相关DB 与 表。
SELECT salary FROM employees WHERE last_name = 'Abel'
SELECT last_name, salary FROM employees WHERE salary > 11000
现有解决方式二:自连接
SELECT e.last_name, e.salary FROM employees e
INNER JOIN employees e2
WHERE e2.last_name = 'Abel'
AND e.salary > e2.salary
现有解决方式三:子查询
SELECT e.last_name, e.salary FROM employees e
WHERE e.salary > (
SELECT salary FROM employees WHERE last_name = 'Abel'
)
注意事项
分类方式1:
我们按内查询的结果返回一条还是多条记录,将子查询分为:单行子查询
、多行子查询
分类方式2:
我们按内查询是否被执行多次,将子查询划分为 相关(或关联)子查询
和 不相关(或非关联)子查询
。
子查询从数据表中查询了数据结果,如果这个数据结果只执行一次
,然后这个数据结果作为主查询的条件进行执行,那么这样的子查询叫做不相关子查询
。
同样,如果子查询需要执行多次,即采用循环的方式,先从外部查询
开始,每次都传入子查询
进行查询,然后再将结果反馈给外部,这种嵌套的执行
方式就称为相关子查询
。
操作符 | 含义 |
---|---|
= | equal to |
> | greater than |
>= | greater than or equal to |
< | less than |
<= | less than or equal to |
<> | not equal to |
题目:
查询工资大于149号员工工资的员工的信息
SELECT employee_id, last_name, salary
FROM employees WHERE salary > (
SELECT salary FROM employees WHERE employee_id = 149
)
题目:
返回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
)
题目:
返回公司工资最少的员工的last_name,job_id和salary
SELECT last_name, job_id, salary
FROM employees WHERE salary = (
SELECT MIN(salary) FROM employees
)
题目:
查询与 141 号或 174 号员工的 manager_id 和 department_id 相同的其他员工的employee_id, manager_id,department_id
实现方式1:不成对比较
SELECT employee_id, manager_id, department_id
FROM employees WHERE manager_id IN(
SELECT manager_id FROM employees WHERE employee_id IN(141, 174)
) AND department_id IN(
SELECT department_id FROM employees WHERE employee_id IN(141, 174)
)
实现方式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)
)
题目:
查询最低工资大于50号部门最低工资的部门id和其最低工资
SELECT department_id, MIN(salary) min_sal
FROM employees
GROUP BY department_id
HAVING min_sal > (
SELECT MIN(salary) AS min_sal FROM employees
WHERE department_id = 50
)
在CASE表达式中使用单列子查询:
题目:
查询员工的employee_id,last_name和location。其中,若员工department_id与location_id为1800的department_id相同,则location为’Canada’,其余则为’USA’。
SELECT
employee_id,
last_name,
(
CASE
department_id
WHEN ( SELECT DISTINCT e.department_id FROM employees e INNER JOIN departments d ON d.department_id = e.department_id WHERE d.location_id = 1800 ) THEN
'Canada' ELSE 'USA'
END
) location
FROM
employees
子查询不返回任何行
SELECT
last_name,
department_id,
salary
FROM
employees
WHERE
job_id = (
SELECT
job_id
FROM
employees
WHERE
last_name = 'Mass'
)
多行子查询使用单行比较符
SELECT employee_id, last_name FROM employees
WHERE salary > (
SELECT MIN(salary) FROM employees GROUP BY department_id
)
操作符 | 含义 |
---|---|
IN | 等于列表中的任意一个 |
ANY | 需要和单行比较操作符一起使用,和子查询返回的某一个 值比较 |
ALL | 需要和单行比较操作符一起使用,和子查询返回的所有 值比较 |
SOME | 实际上是ANY的别名,作用相同,一般常使用ANY |
体会 ANY 和 ALL 的区别
题目:
查询其它job_id中比job_id为‘IT_PROG’部门任一
工资低的员工的员工号、姓名、job_id 以及salary
SELECT employee_id, last_name, job_id, salary
FROM employees WHERE salary < ANY (
SELECT salary FROM employees WHERE job_id = 'IT_PROG'
) AND job_id <> 'IT_PROG'
题目:
查询其它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'
题目:
查询平均工资最低的部门id
方式1:
SELECT department_id FROM employees
GROUP BY department_id
HAVING AVG(salary) = (
SELECT MIN(min_sal) FROM (
SELECT AVG(salary) min_sal FROM employees GROUP BY department_id
) avg_sal_table
)
方式2:
SELECT department_id FROM employees
GROUP BY department_id
HAVING AVG(salary) <= ALL (
SELECT AVG(salary) FROM employees GROUP BY department_id
)
SELECT last_name FROM employees
WHERE manager_id NOT IN (
SELECT manager_id FROM employees
)
如果子查询
的执行依赖于外部查询
,通常情况下都是因为子查询中的表用到了外部的表,并进行了条件关联,因此每执行一次外部查询,子查询都要重新计算一次,这样的子查询就称之为关联子查询
。
相关子查询按照一行接一行的顺序执行,主查询的每一行都执行一次子查询。
题目
:查询员工中工资大于本部门平均工资的员工的last_name,salary和其department_id
方式一:相关子查询
SELECT e.last_name, e.salary, e.department_id FROM employees e
WHERE salary > (
SELECT AVG(salary) FROM employees e2 GROUP BY department_id
HAVING e.department_id = e2.department_id
)
方式二:在 FROM 中使用子查询
SELECT e.last_name, e.salary, e.department_id FROM employees e,
(SELECT department_id, AVG(salary) avg_sal FROM employees GROUP BY department_id) e2
WHERE e.department_id = e2.department_id AND e.salary > e2.avg_sal
from型的子查询:子查询是作为from的一部分,子查询要用()引起来,并且要给这个子查询取别名, 把它当成一张“临时的虚拟的表”来使用。
题目:查询员工的id,salary,按照department_name 排序
在ORDER BY 中使用子查询
SELECT e.employee_id, e.salary FROM employees e
ORDER BY (
SELECT d.department_name FROM departments d
WHERE e.department_id = d.department_id
)
题目
:若employees表中employee_id与job_history表中employee_id相同的数目不小于2,输出这些相同id的员工的employee_id,last_name和其job_id
SELECT * FROM job_history
SELECT e.employee_id, e.last_name, e.job_id FROM employees e
WHERE 2 <= (
SELECT COUNT(*) FROM job_history j
WHERE e.employee_id = j.employee_id
)
如果在子查询中不存在满足条件的行
:
如果在子查询中存在满足条件的行
:
题目
:查询公司管理者的employee_id,last_name,job_id,department_id信息
方式一:
SELECT e.employee_id, e.last_name, e.job_id, e.department_id
FROM employees e, employees e2 WHERE e.manager_id = e2.employee_id
SELECT e.employee_id, e.last_name, e.job_id, e.department_id
FROM employees e INNER JOIN employees e2 ON e.manager_id = e2.employee_id
方式二:
SELECT e.employee_id, e.last_name, e.job_id, e.department_id
FROM employees e WHERE EXISTS (
SELECT * FROM employees e2 WHERE e.manager_id = e2.employee_id
)
题目
:查询departments表中,不存在于employees表中的部门的department_id和department_name
SELECT d.department_id, d.department_name FROM departments d
WHERE NOT EXISTS (
SELECT * FROM employees e WHERE e.department_id = d.department_id
)
UPDATE table1 alias1
SET column = (SELECT expression
FROM table2 alias2
WHERE alias1.column = alias2.column);
使用相关子查询依据一个表中的数据更新另一个表的数据。
题目: 在employees中增加一个department_name字段,数据为员工对应的部门名称
ALTER TABLE employees
ADD(department_name VARCHAR2(14));
UPDATE employees e
SET department_name = (SELECT department_name
FROM departments d
WHERE e.department_id = d.department_id) :
DELETE FROM table1 alias1
WHERE column operator (SELECT expression
FROM table2 alias2
WHERE alias1.column = alias2.column);
问
:自连接
与子查询
两种查询方式有好坏之分吗?
答
:自连接方式好!
题目中可以使用子查询,也可以使用自连接。一般情况建议你使用自连接,因为在许多 DBMS 的处理过程中,对于自连接的处理速度要比子查询快得多。
可以这样理解:子查询实际上是通过未知表进行查询后的条件判断,而自连接是通过已知的自身数据表进行条件判断,因此在大部分 DBMS 中都对自连接处理进行了优化。