AI智能
改变未来

MySQL(2)子查询

含义:出现在其他语句中的select语句,称为子查询或内查询(外部称为主查询)

分类:
按子查询出现的位置:

select后面:##仅仅支持标量子查询from后面:##支持表子查询where或having后面:##标量子查询、列子查询、行子查询(较少)●●exists后面(相关子查询):##表子查询

按功能/结果集的行列数不同:

标量子查询(结果集只有一行一列)(单行子查询)列子查询(结果集只有一列多行)(多行子查询)行子查询(结果集有一行多列)表子查询(结果集一般为多行多列)

一、where 或者 having后面

1、标量子查询(单行子查询)
2、列子查询(多行子查询)
3、行子查询(多列单行)

特点:
1)子查询放在小括号内
2)子查询一般放在条件的右侧
3)标量子查询,一般搭配着单行操作符使用:> < >= <= <> =
列子查询,一般搭配着多行操作符使用: in 、ANY/SOME、ALL
4)子查询优先执行

1、标量子查询

where、having后面的条件是跟一个值进行对比

#案例1:谁的工资比Abel高?

SELECT last_nameFROM employeesWHERE salary > (SELECT salaryFROM employeesWHERE last_name = \'Abel\')

#案例2:返回job_id 与141号员工相同,salary比143号员工多的员工姓名,job_id和工资

SELECT last_name,job_id,salaryFROM employeesWHERE job_id = (SELECT job_idFROM employeesWHERE employee_id = 141)AND salary > (SELECT salaryFROM employeesWHERE employee_id = 143)

#案例3:查询公司工资最少的员工的last_name,job_id和salary

SELECT last_name,job_id,salaryFROM employeesWHERE salary = (SELECT MIN(salary)FROM employees)

#案例4:查询最低工资大于50号部门最低工资的部门id和其最低工资

SELECT department_id,MIN(salary)FROM employeesGROUP BY department_idHAVING MIN(salary) > (SELECT MIN(salary)FROM employeesWHERE department_id = 50)

非法使用标量子查询(如果子查询的结果不是一行一列,则会出错)

2、列子查询(多行子查询)

多行操作符使用:
IN/NOT IN 、ANY/SOME、ALL
a > any(10,20,30) = a > min(10,20,30)
a > all(10,20,30) = a > max(10,20,30)

#案例1:返回location_id 是1400或1700的部门中的所有员工姓名

#1)查询哪些部门的location_id是1400,1700
SELECT DISTINCT department_idFROM departments dWHERE location_id IN (1400,1700)
SELECT last_nameFROM employeesWHERE department_id IN (SELECT DISTINCT department_idFROM departments dWHERE location_id IN (1400,1700))                      #in 也可以用 = any(。。。)#not in 也可以用 <>all(。。。)
可以用内连接的等值连接
SELECT last_nameFROM employees eINNER JOIN departments dON e.department_id = d.department_idWHERE location_id IN (1400,1700)

#案例2:返回其他工种中,比job_id为“IT_PROG\”工种任意一个员工的工资要低的员工的:工号,姓名,job_id,salary

#1)方法一:先找IT_PROG部门的所有工资列,然后查找比这列所有工资都高的员工
SELECT salaryFROM employeesWHERE job_id = \'it_prog\'
SELECT employee_id,last_name,job_id,salaryFROM employeesWHERE salary < ANY(SELECT salaryFROM employeesWHERE job_id = \'it_prog\')AND job_id != \'it_prog\'
#2)方法二:先找IT_PROG的最高工资,然后通过标量子查询查找
SELECT MAX(salary)FROM employeesWHERE job_id = \'it_prog\'
SELECT employee_id,last_name,job_id,salaryFROM employeesWHERE salary < (SELECT MAX(salary)FROM employeesWHERE job_id = \'it_prog\')AND job_id != \'it_prog\'

#案例三:返回其他工种中,比job_id为“IT_PROG\”工种所有员工的工资要低的员工的:工号,姓名,job_id,salary

SELECT employee_id,last_name,job_id,salaryFROM employeesWHERE salary < ALL(SELECT salaryFROM employeesWHERE job_id = \'it_prog\')AND job_id != \'it_prog\'

3、行子查询(一行多列/多行多列)

#案例1:查询员工编号最小,且工资最高的员工信息(有可能不能同时满足两个条件,则不存在)

#两个条件都是用等号

#1)方法一:

SELECT *FROM employeesWHERE employee_id = (SELECT MIN(employee_id)FROM employees)AND salary = (SELECT MAX(salary)FROM employees)
#2)方法二:行子查询
SELECT *FROM employeesWHERE (employee_id,salary)=(SELECT MIN(employee_id),MAX(salary)FROM employees)

二、select后面

#案例1:查询每个部门的员工个数(返回的是departments表格的全部内容+员工个数)

#方法一:子查询
SELECT d.*,(SELECT COUNT(*)FROM employees eWHERE e.department_id = d.department_id#如果此处加GROUP BY d.department_id 或者e.department_id,#则没有员工的部门返回的是null,# FROM 的是employees表,但是如果 group by ,则在employees表中#没有出现的department_id则为null值#此处没有group by也有分组的结果,因为在表连接where语句中,默认了分组结果) AS 员工个数FROM departments d
#错误语句
SELECT d.*,(SELECT COUNT(*)FROM employees e,departments dWHERE e.department_id = d.department_id) AS 员工个数FROM departments d       /*子查询中连接了departments表后,查询出的员工个数结果全部为106,因为此子查询的结果本来就是一个数106(employees表中,一共107行,其中一行无department_id)*/

#方法二:外连接

SELECT d.*,COUNT(e.employee_id)FROM departments dLEFT JOIN employees eON e.department_id = d.department_idGROUP BY d.department_id

#案例2:查询员工号=102的部门名

#方法一:where后面的子查询(标量子查询)
SELECT department_nameFROM departmentsWHERE department_id =  (SELECT department_idFROM employeesWHERE employee_id = 102)
#方法二:内连接
SELECT d.department_nameFROM employees eINNER JOIN departments dON e.department_id = d.department_idWHERE e.employee_id = 178      #178这个员工是没有department_id的,此语句什么都没有返回,因为inner join后,不会有其中一个表中没有的数据
# 方法三:外连接
SELECT d.department_nameFROM employees eLEFT JOIN departments dON e.department_id = d.department_idWHERE e.employee_id = 178		 #返回的是一个null,证明该员工是没有department_id

三、from后面

#案例:查询每个部门的平均工资的工资等级

(1)查询每个部门的平均工资

SELECT AVG(salary) 平均工资,department_idFROM employeesGROUP BY department_id

(2)连接(1)结果集和job_grades表

方法一:普通非等值连接

SELECT ag.*,g.grade_levelFROM (SELECT AVG(salary) 平均工资,department_idFROM employeesGROUP BY department_id ) ag,job_grades gWHERE 平均工资 BETWEEN g.lowest_sal AND g.highest_sal  #此处直接用AVG(salary),不用别名,会报错:Invalid use of group function

方法二:内连接中的非等值连接

SELECT ag.*,g.grade_levelFROM (SELECT AVG(salary) 平均工资,department_idFROM employeesGROUP BY department_id) agINNER JOIN job_grades gON 平均工资 BETWEEN g.lowest_sal AND g.highest_sal

#扩展:查看所有部门的平均工资和工资等级(按照departments表,没有的也显示出来)

#(1)连接departments表和平均工资

SELECT d.*,(SELECT AVG(salary)FROM employees eWHERE d.department_id = e.department_id) agFROM departments d                     #不用group by

#(2)将(1)的结果集连接grade_level

SELECT ag_dep.*,g.grade_levelFROM (SELECT d.*,(SELECT AVG(salary)FROM employees eWHERE d.department_id = e.department_id) agFROM departments d) ag_depLEFT JOIN job_grades gON ag_dep.ag BETWEEN g.lowest_sal AND g.highest_sal   #如果不是用left join,而是用where进行非等值连接,则不会显示没有平均工资的部门信息

四、exists后面(相关子查询)

#1、exists、not exists
#查询的结构是否有值,如果有,则返回1,无则返回0

#案例1:查看

employees

中department_id 是否有空值

SELECT EXISTS(SELECT *FROM employeesWHERE department_id IS NULL)

#扩展:查看

employees

中department_id 有多少空值

SELECT SUM(ISNULL(department_id))FROM employees   #isnull(),空值返回1,非空值返回0
SELECT COUNT(employee_id)FROM employeesWHERE department_id IS NULL

#案例2:查询有员工的部门名

#方法一:用in、any

SELECT department_nameFROM departmentsWHERE department_id IN (SELECT DISTINCT department_idFROM employees)

#方法二:用exists

SELECT department_nameFROM departments dWHERE EXISTS(SELECT *FROM employees eWHERE e.department_id = d.department_id)
**exists 的效率比in的高**子查询中,连接了两个表,employees表中有的department_id,才会exists = True**查询过程:查看d表中第一行department_name,然后查看条件:e表中是否有该department_name的department_id,有则返回department_name,无则不返回。然后查看第二行、第三行...
SELECT *FROM departments d,employees eWHERE d.department_id = e.department_id  #此语句会出现106行数据(其中一行department_id为null的不显示)

#方法三:等值连接

SELECT d.*,COUNT(*)FROM departments d,employees eWHERE d.department_id = e.department_idGROUP BY d.department_id

五、例题

#1、查询和Zlotkey相同部门的员工姓名和工资

SELECT last_name,salaryFROM employeesWHERE department_id = (SELECT department_idFROM employeesWHERE last_name = \'Zlotkey\')

#2、查询工资比公司平均工资高的员工的员工号,姓名和工资

SELECT employee_id,last_name,salaryFROM employeesWHERE salary >(SELECT AVG(salary)FROM employees)

#3、查询各部门中工资比本部门平均工资高的员工的员工号,姓名和工资

#方法一:等值连接

SELECT employee_id,last_name,e.department_id,salary,agFROM (SELECT AVG(salary) ag,department_idFROM employeesGROUP BY department_id) ag_dep,employees eWHERE e.department_id = ag_dep.department_idAND salary > ag_dep.ag

#方法二:内连接

SELECT employee_id,last_name,e.department_id,salary,agFROM employees eINNER JOIN (SELECT AVG(salary) ag,department_idFROM employeesGROUP BY department_id) ag_depON e.department_id = ag_dep.department_idWHERE salary > ag_dep.ag

#4、查询 和 姓名中包含字母u的员工 在相同部门的员工的员工号和姓名

#(1)哪些部门中有员工的姓名含有字母u

SELECT DISTINCT department_idFROM employeesWHERE last_name LIKE \'%u%\'

#(2)连接两个查询

SELECT employee_id,last_name,department_idFROM employeesWHERE department_id IN(SELECT DISTINCT department_idFROM employeesWHERE last_name LIKE \'%u%\')

#5、查询在部门的location_id为1700的部门工作的员工的员工号

SELECT employee_idFROM employeesWHERE department_id IN (SELECT department_idFROM departmentsWHERE location_id = 1700)

#6、查询管理者是K_ing的员工姓名和工资

SELECT employee_idFROM employeesWHERE last_name = \'K_ing\'  #有两个叫king的,100和156
SELECT last_name,salary,manager_idFROM employeesWHERE manager_id = ANY(SELECT employee_idFROM employeesWHERE last_name = \'K_ing\')         #不清楚子查询结果是一个值,还是单列多个值的话,直接用in或者any就行

#7、查询工资最高的员工的姓名,要求first_name和last_name显示为一列,列名为姓名

SELECT CONCAT(first_name,\' \',last_name) 姓名FROM employeesWHERE salary = (SELECT MAX(salary)FROM employees)
赞(0) 打赏
未经允许不得转载:爱站程序员基地 » MySQL(2)子查询