目录
前言
一、实际需求解决
1.方式1:自连接
2.方式2:子查询
二、单行子查询
1.操作符子查询
三、相关子查询
四、自定义语句
五、子查询的问题
1.空值问题
2.非法使用子查询
六、多行子查询
七、聚合函数的嵌套使用
八、多行子查询空值问题
九、相关子查询
1.where中的相关子查询
2.order by 相关子查询
十、exists和not exists
1.第一个例子:
2第二个例子:
总结:
子查询分类
分类方式1
单行子查询和多行子查询
分类方式2
相关子查询和不相关子查询
我们先从一个实际问题入手
谁的工资比Abel高,且Abel的工资是多少?
分解一下
Abel的工资:
SELECT last_name,salary
FROM employees
WHERE last_name = "Abel";
谁的工资比Abel高:
SELECT last_name,salary
FROM employees
WHERE salary > 11000;
SELECT e2.last_name,e2.salary
FROM employees e1 ,employees e2
WHERE e2.salary > e1.salary
AND e1.last_name = "Abel";
自连接并不能解决所有问题
更加通用
SELECT last_name,salary
FROM employees
WHERE salary > (
SELECT salary
FROM employees
WHERE last_name = "Abel"
);
查询工资大于149号员工工资的员工的信息
SELECT employee_id,salary
FROM employees
WHERE salary > (
SELECT salary
FROM employees
WHERE employee_id = 149
);
返回job_id与141号员工相同,salary比143号员工多的员工姓名,job_id和工资
SELECT employee_id,salary
FROM employees
WHERE salary > (
SELECT salary
FROM employees
WHERE employee_id = 143
)
AND
job_id = (
SELECT job_id
FROM employees
WHERE employee_id = 141
);
返回公司工资最少的员工
SELECT employee_id,salary
FROM employees
WHERE salary = (
SELECT MIN(salary)
FROM employees
);
查询与141号员工的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
department_id = (
SELECT department_id
FROM employees
WHERE employee_id = 141
);
我们可以看到上面还包含了141这个人,明显结果不可能有这个
我们加个不等于<>
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;
这个题目还有另外一个写的方式
这个方法的使用场景比较少
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;
查询最低工资大于50号部门最低工资的部门id和其最低工资
SELECT department_id,MIN(salary) FROM employees GROUP BY department_id HAVING MIN(salary) > ( SELECT MIN(salary) FROM employees WHERE department_id = 50 );
题目:显式员工的employee_id,last_name和location
其中,若员工department_id与location_id为1800的department_id相同
则location为'China',区域的为'USA'。
SELECT employee_id,last_name,CASE department_id WHEN (SELECT department_id FROM departments WHERE location_id = 1800) THEN "China" ELSE "USA" END "location" FROM employees;
如果语句逻辑没有问题
可能本身子查询就没有返回值
SELECT last_name,job_id FROM employees WHERE job_id = ( SELECT job_id FROM employees WHERE last_name = "haas" );
排错需要先看子查询是否有值
SELECT job_id FROM employees WHERE last_name = "haas"
本身没有返回值,所以为空是正常的
SELECT employee_id,last_name FROM employees WHERE SALARY = ( SELECT MIN(salary) FROM employees GROUP BY department_id);
这里的错误是因为“=”是一个单行子查询,但这里子查询返回的结果是一堆元组,所以就会有报错的问题
前面那个逻辑错误是单行子查询的逻辑错误
我们解决这个问题可以使用多行子查询的方法
我们把上面那个逻辑错误的修改一下
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
我们常规的语句思路就是先求出每个部门的平均工资
SELECT AVG(salary) avg_sal FROM employees GROUP BY department_id;
我们尝试对外嵌套函数
SELECT MIN(AVG(salary)) avg_sal FROM employees GROUP BY department_id;
mysql聚合函数是不支持嵌套使用的
我们要解决这个问题就需要把内部的平均值聚合函数结果变成一张表,然后对表内数据进行最小值查询
SELECT MIN(avg_sal) FROM( SELECT AVG(salary) avg_sal FROM employees GROUP BY department_id ) dept_avg_sal;
我们现在已经得到平均部门最小的工资了
我们需要得到部门id
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 ) dept_avg_sal );
有第二个方法
SELECT department_id FROM employees GROUP BY department_id HAVING AVG(salary) <= ALL( SELECT AVG(salary) avg_sal FROM employees GROUP BY department_id );
查询不是管理者的人的last_name
正常的语句
SELECT last_name FROM employees WHERE employee_id NOT IN ( SELECT MANAGER_ID FROM employees );
得到的是空值
我们排错发现子查询是有输出的
这里的问题在于值里面有空值,所以最后会有空
我们加一个条件
SELECT last_name FROM employees WHERE employee_id NOT IN ( SELECT MANAGER_ID FROM employees WHERE MANAGER_ID IS NOT NULL );
就可以正常得到结果
相关子查询执行流程
查询员工中工资大余本部门平均工资的员工的last_name,salary和其的department_id
SELECT last_name,salary,department_id FROM employees e1 WHERE SALARY > ( SELECT AVG(SALARY) FROM employees e2 WHERE department_id = e1.`DEPARTMENT_ID` );
这个题目有另外一个方法
我们用两张表进行比较
一张是员工表,一张是已经过滤出每个部门平均工资的表
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) T WHERE e.`DEPARTMENT_ID` = T.`DEPARTMENT_ID` AND e.`SALARY` > T.avg_sal;
查询员工的id,salary,按照department_name 排序
SELECT e1.employee_id,e1.salary FROM employees e1 ORDER BY (SELECT department_name FROM departments e2 WHERE e1.`DEPARTMENT_ID` = e2.`DEPARTMENT_ID` ) ASC;
注意这里有个结论
查询公司管理者的employee_id,last_name,job_id,department_id信息
方式1不用exists的方法
自连接方法
SELECT DISTINCT mgr.employee_id,mgr.last_name,mgr.job_id,mgr.department_id
FROM employees emp JOIN employees mgr
ON emp.MANAGER_ID = mgr.EMPLOYEE_ID;
子查询方法
SELECT employee_id,last_name,job_id,department_id
FROM employees
WHERE EMPLOYEE_ID IN (
SELECT DISTINCT MANAGER_ID
FROM employees
);
exist方法
SELECT employee_id,last_name,job_id,department_id
FROM employees
WHERE EMPLOYEE_ID exi (
SELECT DISTINCT MANAGER_ID
FROM employees
);
查询departments表中,不存在于employees表中的部门的department_id和department_name
方式1
前面讲过
SELECT employee_id , department_name
FROM employees e RIGHT JOIN departments d
ON e.department_id = d.department_id
WHERE e.employee_id IS NULL;
方法2
先找存在于employees表中的部门的department_id和department_name
SELECT department_id,department_name
FROM departments d
WHERE EXISTS(
SELECT *
FROM employees e
WHERE d.DEPARTMENT_ID = e.DEPARTMENT_ID
);
我们直接用not exists就可以了
SELECT department_id,department_name
FROM departments d
WHERE NOT EXISTS(
SELECT *
FROM employees e
WHERE d.DEPARTMENT_ID = e.DEPARTMENT_ID
);
学了这么多子查询的嵌套方法
我们抛一个问题:
自连接和子查询的方法那个更优呢?
答案是子查询更优一些
摆了一个星期,去寻找诗和远方了,希望这周能高强度更新,小伙伴们给点鼓励把