MySQL——子查询用法

MySQL——子查询用法

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
    );
### MySQL子查询分页技术的实现方法 在 MySQL 数据库中,当需要基于子查询的结果集进行分页操作时,可以通过 `LIMIT` 和 `OFFSET` 子句来完成这一需求。这种方法的核心在于将子查询作为外部查询的数据源,并在外层应用分页逻辑。 #### 使用 LIMIT 和 OFFSET 进行子查询分页 以下是一种常见的子查询分页模式: ```sql SELECT * FROM ( SELECT id, name, age FROM users WHERE status = 'active' -- 假设这是过滤条件 ORDER BY created_at DESC ) AS subquery LIMIT 10 OFFSET 20; ``` 上述 SQL 查询展示了如何对外部子查询结果进行分页[^1]。其中: - **子查询部分** (`subquery`) 负责筛选符合条件的数据并按指定顺序排列。 - 外层查询则利用 `LIMIT` 和 `OFFSET` 对子查询返回的结果进一步截取所需的部分。 需要注意的是,在某些情况下,如果子查询涉及大量数据,则可能会导致性能下降。因此建议优化索引设计以及合理控制子查询范围以提升效率[^3]。 #### 高效替代方案——窗口函数 (适用于 MySQL 8.0+) 对于支持窗口函数的 MySQL 版本(即 8.0 及以上),可以考虑采用更高效的分页策略。例如使用 ROW_NUMBER() 创建虚拟编号列来进行精确定位: ```sql WITH paginated_data AS ( SELECT *, ROW_NUMBER() OVER(ORDER BY created_at DESC) as row_num FROM users WHERE status='active' ) SELECT * FROM paginated_data WHERE row_num BETWEEN 21 AND 30; -- 表示第3页,每页显示10条记录 ``` 此方法避免了传统 `LIMIT/OFFSET` 的潜在缺陷 —— 即随着偏移量增大而带来的扫描成本增加问题[^2] 。它通过预先分配每一行唯一的序号简化后续检索过程。 --- ### 总结 无论是借助经典的 `LIMIT`/`OFFSET` 组合还是现代的窗口函数特性,都可以有效解决 MySQL 子查询场景下的分页难题。然而实际开发过程中还需综合考量业务特点、硬件资源状况等因素选取最适合的技术路径。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

万里顾—程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值