postgresql-子查询

子查询简介

子查询(Subquery)是指嵌套在其他 SELECT、INSERT、UPDATE 以及 DELETE 语句中的
查询语句
子查询的作用与多表连接查询有点类似,也是为了从多个关联的表中返回或者过滤数据。例
如,我们想要知道哪些员工的月薪大于平均月薪,可以通过子查询实现

select e.first_name, e.last_name, e.salary
 from employees e
where salary > (select avg(salary) from employees);

在这里插入图片描述
子查询必须位于括号中,也称为内查询,包含子查询的查询语句被称为外查询。除了 WHERE
子句之外,其他子句中也可以使用子查询,例如 SELECT 列表、FROM 子句等

派生表

FROM 子句中的子查询被称为派生表(Derived table)

SELECT column1, column2, ...
 FROM (subquery) AS table_alias;

其中子查询相当于创建了一个临时表 table_alias

-- 获取每个部门的总月薪
select d.department_name,
 ds.sum_salary
 from departments d
 join (select department_id,
 sum(salary) as sum_salary
 from employees
 group by department_id) ds
 on (d.department_id = ds.department_id);

子查询返回了部门编号和部门月薪合计;然后再和 departments 表进行连接查询

IN 操作符

如果 WHERE 子查询返回多个记录,可以使用 IN 操作符进行条件过滤:

-- in 
-- 存在 2008 年 01 月 01 日以后入职员工的部门
select *
from cps.public.departments d 
where d.department_id in 
(
select distinct e.department_id 
from cps.public.employees e 
where e.hire_date >= date '2008-01-01'
);

在这里插入图片描述

ALL 操作符

ALL 操作符与比较运算符一起使用,可以将一个值与子查询返回的列表进行比较:

-- all
-- 返回了月薪比销售部门(department_id = 80)所有员工都高的员工
select e.first_name ,
e.salary 
from cps.public.employees e 
where e.salary > all
(select e2.salary from cps.public.employees e2 where e2.department_id= 80);

上述sql等价于下面的sql

-- all
-- 返回了月薪比销售部门(department_id = 80)所有员工都高的员工
select e.first_name ,
e.salary 
from cps.public.employees e 
where e.salary > 
(select max(e2.salary)  from cps.public.employees e2 where e2.department_id= 80);

在这里插入图片描述

ANY 操作符

ANY 操作符和 ALL 操作符使用方法类似,只是效果不同:

-- any
-- 返回了月薪比销售部门(department_id = 80)任何一个员工都高的员工
select e.first_name ,
e.salary 
from cps.public.employees e 
where e.salary > 
(select min(e2.salary)  from cps.public.employees e2 where e2.department_id= 80);

上述sql等价于下面的sql

-- any
-- 返回了月薪比销售部门(department_id = 80)任何一个员工都高的员工
select e.first_name ,
e.salary 
from cps.public.employees e 
where e.salary > any
(select e2.salary  from cps.public.employees e2 where e2.department_id= 80);

在这里插入图片描述
另外,SOME 和 ANY 是同义词。some的效果和any是一样的

关联子查询

有另一类子查询,它们会引用外部查询中的列,因而与外部查询产生关联,被称为关联子查询

/*
 * 子查询中使用了外查询的字段(e.department_id)。对于外部查询中的每个员工,
 * 运行子查询返回他/她所在部门的平均月薪,然后传递给外部查询进行判断
 * */
-- 返回月薪大于所在部门平均月薪的员工
select 
e.first_name,
e.salary 
from cps.public.employees e 
where e.salary >
(select avg(e2.salary) from cps.public.employees e2 where e2.department_id  = e.department_id);

在这里插入图片描述
关联子查询对于外查询中的每一行都会运行一次(数据库可能会对此进行优化),而非
关联子查询在整个查询运行时只会执行一次

横向子查询

一般来说,子查询只能引用外查询中的字段,而不能使用同一层级中其他表中的字段。例如:

/**/
select 
d.department_name ,t.sum_sal
from cps.public.departments d 
join (
select sum(e.salary) sum_sal from cps.public.employees e where e.department_id = d.department_id 
) t on true;

在这里插入图片描述
以上语句在 JOIN 中引用了左侧 departments 表中的字段,产生了语法错误。为此,我们需
要使用横向子查询(LATERAL subquery)。通过增加 LATERAL 关键字,子查询可以引用左侧
表中的列:

/*
 * 每个部门的名称和总月薪
 * */
select 
d.department_name ,t.sum_sal
from cps.public.departments d 
cross join lateral (
select sum(e.salary) sum_sal from cps.public.employees e where e.department_id = d.department_id 
) t;

在这里插入图片描述

EXISTS 操作符

EXISTS 操作符用于检查子查询结果的存在性。如果子查询返回任何结果,EXISTS 返回 True;
否则,返回 False

-- EXISTS
select * 
from cps.public.departments d 
where exists 
(select 1 from cps.public.employees e
where e.department_id = d.department_id 
and e.hire_date > date '2008-01-01'
);

在这里插入图片描述

-- not exists不存在
select * 
from cps.public.departments d 
where not exists 
(select 1 from cps.public.employees e
where e.department_id = d.department_id 
and e.hire_date > date '2008-01-01'
);

在这里插入图片描述
[NOT] IN 用于检查某个值是否属于(=)子查询的结果列表,[NOT] EXISTS 只检查子查询
结果的存在性。如果子查询的结果中存在 NULL,NOT EXISTS 结果为 True;但是,NOT IN 结
果为 False,因为 NOT (X = NULL) 的结果为 NULL

-- in 在什么取值范围内
select *
from cps.public.departments d 
where d.department_id  in 
(select distinct e.department_id  from cps.public.employees e)

在这里插入图片描述

-- not in 不属于子查询结果列
select *
from cps.public.departments d 
where d.department_id not in 
(select distinct e.department_id  from cps.public.employees e)

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Java_Fly1/article/details/132702117