MySQL查询语句之子查询(六)

文章目录

  • 一、where或having后面
    • 1.1 标量子查询
    • 1.2 列子查询(多行子查询)
    • 1.3 行子查询(结果集一行多列或多行多列)
  • 二、select后面
  • 三、from后面
  • 四、exists后面(相关子查询)

子查询含义:
    出现在其他语句的select语句,称为子查询或内查询
    外部的查询语句,称为主查询或外查询
分类:
按子查询出现的位置:
    select后面:
          仅仅支持标量子查询
    from后面:
          支持表子查询
    where或having后面:★★★
          标量子查询(单行)√
          列子查询 (多行)√
          行子查询(用的少)
    exists后面(相关子查询)
          表子查询
按结果集的行列数不同:
    标量子查询(结果集只有一行一列)
    列子查询(结果集一列多行)
    行子查询(结果集一行多列)
    表子查询(结果集一般为多行多列)

一、where或having后面

支持:
1.标量子查询(单行子查询)
2.列子查询(多行子查询)
3.行子查询(多行多列)
特点:
①子查询放在小括号内
②子查询一般放在条件的右侧
③标量子查询,一般单行操作符使用>,<,=,>=,<=,<>
列子查询,一般搭配多行操作符使用in,any/sum,all
④子查询的执行优先于主查询的执行,主查询的条件用到了子查询的结果

1.1 标量子查询

案例1: 谁的工资比Abel高?
step1:查询Abel的工资

show databases;
use myemployees;
select salary from employees where last_name = 'Abel';

step2:查询员工信息,满足salary>step1的结果

select * from employees
where salary >(
	select salary 
    from employees 
    where last_name = 'Abel'
); # where后面标量子查询(结果集是一个数据),放在()内

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

select job_id
from employees
where employee_id=141;

step2:查询143号员工的salary

select salary
from employees
where employee_id=143;

step3:查询员工的姓名,job_id和工资,要求job_id=step1并且salary>step2

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
);

案例3: 返回公司工资最少的员工last_name,job_id,salary
step1:查询公司的最低工资

select min(salary)
from employees;

step2:查询last_name,job_id,和salary,要求salary=step1结果

select last_name,job_id,salary
from employees
where salary=(
	select min(salary)
	from employees
);

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

select min(salary)
from employees
where department_id=50;

step2:查询每个部门的最低工资

select min(salary),department_id
from employees
group by department_id;

step3:筛选step2满足min(salary)>step1

select min(salary),department_id
from employees
group by department_id
having min(salary)>(
	select min(salary)
	from employees
	where department_id=50
); # 子查询在having之后

非法使用子查询

select min(salary),department_id
from employees
group by department_id
having min(salary)>(
	select salary
	from employees
	where department_id=50
); # 不是一行一列

1.2 列子查询(多行子查询)

案例1: 返回location_id是1400或1700的部门中的所有员工姓名
step1:查询location_id是1400或1700的部门编号

select department_id
from departments
where location_id in (1400,1700); # 两行

step2:查询员工姓名,要求部门号是step1列表中的某一个

select last_name
from employees
where department_id in(
	select distinct department_id
	from departments
	where location_id in (1400,1700)
); # 将in换成 =any 效果一样;not in换成<>all效果一样

案例2: 返回其它工种中比job_id为‘IT_PROG’工种部门任一工资低的员工的员工号、姓名、job_id以及salary
step1: 查询job_id为‘IT_PROG’部门任一工资

select distinct salary
from employees
where job_id='IT_PROG';

step2: 查询员工号、姓名、job_id以及salary,salary

select last_name,employee_id,job_id,salary
from employees
where salary < any (
	select distinct salary
	from employees
	where job_id='IT_PROG'
)and job_id<>'IT_PROG'; # 工种不是IT_PROG且工资低于IT_PROG任一工资的员工

或者:

select last_name,employee_id,job_id,salary
from employees
where salary < (
	select max(salary)
	from employees
	where job_id='IT_PROG'
)and job_id<>'IT_PROG'; # 去掉any,里面为max也行

案例3: 返回其它部门中比job_id为‘IT_PROG’部门所有工资都低的员工的员工号、姓名、job_id 以及salary

select last_name,employee_id,job_id,salary
from employees
where salary < all (
	select distinct salary
	from employees
	where job_id='IT_PROG'
)and job_id<>'IT_PROG'; # 比IT_PROG部门所有(all)都低

select last_name,employee_id,job_id,salary
from employees
where salary < (
	select min(salary)
	from employees
	where job_id='IT_PROG'
)and job_id<>'IT_PROG'; # 去掉all,里面为min也行

1.3 行子查询(结果集一行多列或多行多列)

案例: 查询员工编号最小且工资最高的员工信息

select *
from employees
where (employee_id,salary)=(
	select min(employee_id),max(salary)
	from employees
);

传统做法:
s1:查询最小的员工编号

show databases;
use myemployees;
select min(employee_id)
from employees;

s2:查询最高工资

select max(salary)
from employees;

s3:查询员工信息

select * 
from employees
where employee_id=(
	select min(employee_id)
	from employees
)and salary=(
	select max(salary)
	from employees
); # 不用and,使两个字段放在()里亦可

二、select后面

仅仅支持标量子查询
案例1: 查询每个部门的员工个数

select d.*,(
	select count(*)
	from employees e
	where e.department_id=d.department_id
) 个数 # 个数为标量
from departments d;

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

select (
	select department_name
	from departments d
	inner join employees e
	on d.department_id=e.department_id
	where e.employee_id=102
) 部门名; # 里面是部门名

三、from后面

将子查询结果充当一张表,要求必须起别名
案例: 查询每个部门的平均工资的工资等级
s1:查询每个部门的平均工资

select avg(salary),department_id
from employees
group by department_id;

select * from job_grades;

s2:连接s1的结果集和job_grades表,筛选条件平均工资between lowest_sal and highest_sal

select ag_dep.*,g.grade_level
from (
	select avg(salary) ag,department_id
	from employees
	group by department_id
) ag_dep
inner join job_grades g
on ag_dep.ag between lowest_sal and highest_sal;

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

语法:
exists(完整的查询语句)
结果:
1:存在,0:不存在

select exists(select employee_id from employees where salary = 30000);

案例1: 查询有员工的部门名
in(能使用exists就能用in)

select department_name
from departments d
where d.department_id in (
	select department_id
	from employees
); # 员工表中的部门名集合里是不是部门表中也有

== exists==

select department_name
from departments d
where exists(
   select *
   from employees e
   where d.department_id=e.department_id
);

案例2: 查询没有女朋友的男神信息
not in

use girls;
select bo.*
from boys bo
where bo.id not in(
	select boyfriend_id
	from beauty
);

not exists

select bo.*
from boys bo
where not exists(
	select boyfriend_id
	from beauty b
	where bo.id=b.boyfriend_id
);

你可能感兴趣的:(MySQL查询语句之子查询(六))