MySQL——子查询用法

「这是我参与2022首次更文挑战的第38天,活动详情查看:2022首次更文挑战

1、子查询概述

子查询简介

子查询指一个查询语句嵌套在另一个查询语句内部的查询,内部的查询是外部查询的条件,这个特性从MySQL4.1开始引入。

SQL中子查询的使用大大增强了SELECT查询的能力,因为很多时候查询需要从结果集中获取数据,或者需要从同一个表中先计算得出一个数据结果,然后与这个数据结果(可能是某个标量,也可能是某个集合)进行比较。

子查询基本使用

语法:

SELECT -- 主查询
    select_list
FROM
    table
WHERE
    expr operator > (SELECT -- 子查询
            select_list
        FROM
            table);
复制代码

子查询(内查询)在主查询之前执行完成。

子查询的结果被主查询(外查询)使用。

注意事项:

  • 子查询要包含在括号内

  • 将子查询放在比较条件的右侧

  • 单行操作符对应单行子查询,多行操作符对应多行子查询

子查询的分类

按子查询的结果返回一条还是多条记录,将子查询分为单行子查询和多行子查询。

按子查询是否被执行多次,将子查询划分为相关(或关联)子查询和不相关(或非关联)子查询。

2、子查询的使用

2.1、单行子查询

单行比较操作符

=等于,>大于,>=大于等于,<小于,<=小于等于,<>不等于

使用实例

-- 查找薪水大于所有员工平均薪水的员工
SELECT employee_id, first_name, last_name, salary
FROM employees
WHERE salary > (
    SELECT AVG(salary) FROM employees);

-- 查询工资大于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
    );

-- 查询与147号员工的manager_id和department_id相同的其他员工的employee_id,manager_id,department_id
select employee_id,manager_id,department_id
from employees
where manager_id = (
    select manager_id from employees where employee_id = 147
    )
and department_id = (
    select department_id from employees where employee_id = 147
    )
and employee_id <> 147;    
    
-- 查询最低工资大于50号部门最低工资的部门id和其最低工资
select department_id,min(salary) min_salary
from employees
where department_id is not null
group by department_id
having min_salary > (
    select min(salary) from employees where department_id = 50
    );
    
    
复制代码

2.2、多行子查询

多行子查询比较操作符

在这里插入图片描述

使用实例

-- 查找属于位置ID为1700的所有员工
SELECT
    employee_id, first_name, last_name
FROM
    employees
WHERE
    department_id IN (SELECT
            department_id
        FROM
            departments
        WHERE
            location_id = 1700)
ORDER BY first_name , last_name;

-- 返回其它job id中比job id为'IT_PROG’部门任一工资低的员工的员工号姓名、job id以及salary
select 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 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
-- 方式一:
select department_id,avg(salary) from employees group by department_id order by avg(salary) limit 1;
-- 方式二:
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
         ) t_dept_avg_sal
    )
-- 方式三:
select department_id
from employees
group by department_id
having avg(salary) <= all (
    select avg(salary) from employees group by department_id
);

-- 查询员工表中是领导的员工信息
select employee_id,last_name,manager_id
from employees
where employee_id in (
    select manager_id from employees
    );
    
-- 查询员工表中不是领导的员工信息
select employee_id,last_name,manager_id
from employees
where employee_id not in (
    select manager_id from employees where manager_id is not null
    );
复制代码

2.3、相关子查询

如果子查询的执行依赖于外部查询,通常情况下都是因为子查询中的表用到了外部的表,并进行了条件关联,因此每执行一次外部查询,子查询都要重新计算一次,这样的子查询就称之为关联子查询。

相关子查询按照一行接一行的顺序执行,主查询的每一行都执行一次子查询。

使用实例

-- 查询员工中工资大于本部门平均工资的员工的last_name, salary和其department_id
-- 方式一
select last_name,salary,department_id
from employees e1
where salary > (
    select avg(salary) from employees e2 where e1.department_id = e2.department_id
    );
-- 方式二
select last_name,salary,e.department_id
from employees e ,(select department_id,avg(salary) avg_sal from employees group by department_id) t_dept_avg_sal
where e.department_id = t_dept_avg_sal.department_id
and e.salary > t_dept_avg_sal.avg_sal;

-- 查询员工的id,salary,按照department_name排序
select employee_id,salary
from employees e
order by (
    select department_name from departments d where e.department_id = d.department_id
             );
                     
复制代码

EXISTS与NOT EXISTS

EXISTS运算符用于指定子查询中是否存在满足条件的行,

如果子查询包含任何行,则EXISTS运算符返回true。 否则它返回false

EXISTS运算符在找到行后立即终止查询处理,因此,可以利用EXISTS运算符的此功能来提高查询性能

NOT EXISTS 表示如果不存在某种条件,则返回true,否则返回true。

使用实例:

-- 查找管理者的id,姓名,工作和部门id
select employee_id,last_name,job_id,department_id
from employees e1
where exists(
    select * from employees e2 where e1.employee_id = e2.manager_id
          )
          
-- 查询departments表中,不存在于employees表中的部门的department_id和department_name
-- 方式一
select department_id,department_name
from departments d
where not exists(
    select * from employees e where d.department_id = e.department_id
    );
-- 方式二
select d.department_id,department_name
from departments d left join employees e on d.department_id = e.department_id
where e.department_id is null;          
          
复制代码

子查询练习题

#1.查询和Zlotkey相同部门的员工姓名和工资
select last_name,salary
from employees
where department_id in (
    select department_id from employees where last_name = 'Zlotkey'
    )
and last_name <> 'Zlotkey';

#2.查询工资比公司平均工资高的员工的员工号,姓名和工资。
select employee_id,last_name,salary
from employees
where salary > (
    select avg(salary) from employees
    );

#3.选择工资大于所有JOB_ID = 'SA_MAN'的员工的工资的员工的last_name,job_id, salary
select last_name,job_id,salary
from employees
where salary > (
    select max(salary) from employees where job_id = 'SA_MAN'
    );

#4.查询和姓名中包含字母u的员工在相同部门的员工的员工号和姓名
select employee_id,last_name
from employees
where department_id in (
    select department_id from employees where last_name like '%u%'
    );

#5.查询在部门的location_id为1700的部门工作的员工的员工号
select employee_id
from employees e
where department_id in (
    select department_id from departments where location_id = 1700
    );

#6.查询管理者是King的员工姓名和工资
select last_name,salary
from employees
where  manager_id in (
    select employee_id from employees where last_name = 'K_ing'
    );


#7.查询工资最低的员工信息: last_name,salary
select last_name,salary
from employees
order by salary
limit 1;

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

#8.查询平均工资最低的部门信息
-- 方式一:
select * from departments
where department_id = (
    select department_id
    from employees
    group by department_id
    order by avg(salary)
    limit 1
    );
-- 方式二:
select * from departments
where department_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) t_sal
    )
);
-- 方式三:
select * from departments
where department_id = (
    select department_id
    from employees
    group by department_id
    having avg(salary) <= all (select avg(salary) from employees group by department_id)
    );

#9.查询平均工资最低的部门信息和该部门的平均工资,子查询可以写在查询字段里面
select d.* ,(select avg(salary) from employees where department_id = d.department_id) avg_sal
from departments d
where department_id = (
    select department_id
    from employees
    group by department_id
    having avg(salary) <= all (select avg(salary) from employees group by department_id)
    );

#10.查询平均工资最高的job 信息
-- 方式一:
select * from jobs
where job_id = (
    select job_id
    from employees
    group by job_id
    having avg(salary) >= all (
        select avg(salary) from employees group by job_id )
    );
-- 方式二:
select * from jobs
where job_id = (
    select job_id
    from employees
    group by job_id
    order by avg(salary) desc
    limit 1
    );

#11.查询平均工资高于公司平均工资的部门有哪些?
select distinct department_id
from employees
where department_id is not null
group by department_id
having avg(salary) > (
    select avg(salary) from employees
    );

#12.查询出公司中所有manager 的详细信息
-- 方式一
select employee_id,last_name,salary,department_id
from employees e1
where exists(
    select * from employees e2 where e1.employee_id = e2.manager_id
          );
-- 方式二
select distinct man.employee_id,man.last_name,man.salary,man.department_id
from employees emp
join employees man
on emp.manager_id = man.employee_id  ;

-- 方式三 子查询
select employee_id,last_name,salary,department_id
from employees
where employee_id in (
    select distinct manager_id from employees
    );

#13.查各个部门最高的工资中 最低的那个部门的最低工资多少
-- 方式一:
select department_id,min(salary) from employees
where department_id = (
    select department_id from employees
    group by department_id
    having max(salary) = (
    select min(max_sal)
        from employees e, ( select max(salary) max_sal
                            from employees
                            where department_id is not null
                            group by department_id ) t_min_sal
    ));
-- 方式二:
select department_id,min(salary) from employees
where department_id = (
    select department_id from employees
    group by department_id
    having max(salary) <= all (
        select max(salary) from employees
        group by department_id)
    );
-- 方式三:
select min(salary) from employees
where department_id = (
    select department_id from employees
    group by department_id
    having max(salary) = (
       select max(salary) from employees
       group by department_id
       order by max(salary)
       limit 1 )
    );
-- 方式四:
select min(salary) from employees e,( select department_id, max(salary) from employees
                                    group by department_id
                                    order by max(salary)
                                    limit 1) t_max_sal
where e.department_id = t_max_sal.department_id;
#14.查询平均工资最高的部门的 manager的详细信息: last_name,department_id,email,salary
-- 方式一:
select last_name,department_id,email,salary
from employees
where employee_id = (
    select manager_id
    from departments
    where department_id = (
        select department_id from employees
        group by department_id
        order by avg(salary) desc
        limit 1)
    );
-- 方式二:
select last_name,department_id,email,salary
from employees
where employee_id = (
select manager_id from departments
where department_id = (
    select department_id
    from employees
    group by department_id
    having avg(salary) >= all (
        select avg(salary)
        from employees
        where department_id is not null
        group by department_id)
    )
 );
-- 方式三:
select last_name,department_id,email,salary from employees
where employee_id = (
    select manager_id from departments
    where department_id = (
        select department_id
        from employees
        group by department_id
        having avg(salary) = (
           select max(avg_sal) from (select avg(salary) avg_sal
           from employees
           where department_id is not null
           group by department_id) t_avg_sql
    ))
 );
#15.查询部门的部门号,其中不包括job_id是"ST_CLERK"的部门号
-- 方式一:
select department_id
from departments
where department_id not in (
    select distinct department_id
    from employees e1
    where job_id = 'ST_CLERK'
    );
-- 方式二:
select department_id
from departments d
where  not exists (
    select *
    from employees e1
    where d.department_id = e1.department_id and job_id = 'ST_CLERK'
    );
#16.选择所有没有管理者的员工的last_name
select last_name
from employees e1
where not exists(
    select * from employees e2 where e1.manager_id = e2.employee_id
    );

#17.查询员工号、姓名、雇用时间、工资,其中员工的管理者为 'De Haan '
-- 方式一:自连接
select e1.employee_id,e1.last_name,e1.hiredate,e1.salary
from employees e1,employees e2
where e1.manager_id = e2.employee_id and e2.last_name = 'De Haan';

-- 方式二:子查询
select employee_id,last_name,hiredate,salary
from employees
where manager_id in (
    select employee_id from employees where last_name = 'De Haan'
    );

#18.查询各部门中工资比本部门平均工资高的员工的员工号,姓名和工资(相关子查询)
-- 方式一:
select employee_id,salary,last_name
from employees e1
where salary > (
    select avg(salary) from employees e2 where e1.department_id = e2.department_id
    );
-- 方式二:
select employee_id,salary,last_name
from employees e,(select department_id,avg(salary) avg_sal from employees group by department_id) t_avg_sal
where e.department_id = t_avg_sal.department_id and e.salary > t_avg_sal.avg_sal;

#19.查询每个部门下的部门人数大于5的部门名称(相关子查询)I
select department_name
from departments d
where 5 < (
    select count(*) from employees e where e.department_id = d.department_id
    );
#20.查询每个国家下的部门个数大于2的国家编号(相关子查询)
select country_id
from locations l
where 2 < (
    select count(*) from departments d where l.location_id = d.location_id
    );
复制代码

Guess you like

Origin juejin.im/post/7068447320261525512