当前位置: 首页 > news >正文

PostgreSQL15——子查询

子查询

  • 一、派生表
  • 二、IN操作符
  • 三、ALL操作符
  • 四、ANY操作符
  • 五、关联子查询
  • 六、横向子查询
  • 七、EXISTS 操作符

子查询(Subquery)是指嵌套在其他SELECT、INSERT、UPDATE 以及 DELETE 语句中的查询语句。

一、派生表

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_salaryFROM employeesgroup by department_id) ds
ON d.department_id = ds.department_id;

在这里插入图片描述

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

二、IN操作符

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

SELECT d.department_id, d.department_name
FROM departments d
WHERE d.department_id in (SELECT department_id FROM employees WHEREhire_date >= date '2008-01-01');

在这里插入图片描述

以上查询返回了存在 2008 年01 月 01 日以后入职员工的部门。如果想要返回包含该日期之前入职的员工的部门,可以使用 NOT IN 操作符。

三、ALL操作符

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

SELECT first_name, last_name, salary
FROM employees
WHERE salary > all (SELECT salary FROM employees WHERE department_id = 80);

在这里插入图片描述

以上语句返回了月薪比销售部门(department_id = 80)所有员工都高的员工。其他比较运算符也可以与 ALL 进行组合,例如 salary < ALL 表示月薪比销售部门所有员工都低的员工。

四、ANY操作符

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

SELECT first_name, last_name, salary
FROM employees
WHERE salary > any (SELECT salary FROM employees WHERE department_id = 80);

在这里插入图片描述

以上语句返回了月薪比销售部门(department_id = 80)任何员工高的员工。ANY 也可以和其他比较运算符一起使用,例如= ANY 实际上和 IN 的作用相同。另外,SOME 和 ANY 是同义词。

五、关联子查询

以上所有示例中的子查询都可以独立运行,因为它们没有使用到外部查询中的信息。还有另一类子查询,它们会引用外部查询中的列,因而与外部查询产生关联,被称为关联子查询。

以下语句返回月薪大于所在部门平均月薪的员工:

SELECT first_name, last_name, salary
FROM employees o
WHERE o.salary > (SELECT avg(salary) FROM employees i WHERE i.department_id = o.department_id);

在这里插入图片描述

我们可以看到,子查询中使用了外查询的字段(o.department_id)。对于外部查询中的每个员工,运行子查询返回他/她所在部门的平均月薪,然后传递给外部查询进行判断。

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

以下语句在 SELECT 列表中使用关联子查询,返回每个部门的总月薪,和上文第一个示例相同:

SELECT d.department_name, (SELECT SUM(salary)FROM employees eWHERE e.department_id = d.department_id) AS sum_salary
FROM departments d
ORDER BY d.department_name;

在这里插入图片描述

六、横向子查询

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

-- Error case
SELECT d.department_name, t.avg_salary
FROM departments d
JOIN (SELECT avg(e.salary) AS avg_salaryFROM employees eWHERE e.department_id = d.department_id) t;ERROR:  syntax error at or near ";"
LINE 7:  WHERE e.department_id = d.department_id) t;^ SQL state: 42601
Character: 177

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

SELECT d.department_name, t.sum_salary
FROM departments d
CROSS JOIN LATERAL (SELECT sum(e.salary) AS sum_salaryFROM employees eWHERE e.department_id = d.department_id) t;

在这里插入图片描述

以上语句同样返回了每个部门的名称和总月薪。

七、EXISTS 操作符

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

SELECT d.department_id, d.department_name
FROM departments d
WHERE exists (SELECT 1 FROM employees WHERE department_id = d.department_id and hire_date >= date '2008-01-01');

在这里插入图片描述

以上示例返回了存在 2008 年 01 月 01 日以后入职员工的部门,与上文中的 IN 操作符示例相同。

NOT EXISTS 操作符执行相反的操作,即子查询不返回任何结果,NOT EXISTS 返回 True;否则,返回False。

NOT IN 用于检查某个值是否属于(=)子查询的结果列表,

NOT EXISTS 只检查子查询结果的存在性。如果子查询的结果中存在 NULL,NOT EXISTS 结果为 True;但是,NOT IN 结
果为 False,因为 NOT (X = NULL) 的结果为 NULL。例如:

SELECT d.department_id, d.department_name
FROM departments d
WHERE not exists (SELECT 1 FROM employees WHERE department_id = d.department_id);

在这里插入图片描述

以上语句查找没有任何员工的部门,结果返回了 16 条记录。如果使用 NOT IN 操作符:

SELECT d.department_id, d.department_name
FROM departments d
WHERE d.department_id not in (SELECT department_id FROM employees);

在这里插入图片描述

查询没有返回任何结果,因为有一个员工不属于任何部门,导致子查询的结果中包含NULL:

SELECT first_name, last_name, department_id
FROM employees
WHERE department_id is null;

在这里插入图片描述

http://www.xdnf.cn/news/1390087.html

相关文章:

  • 基于SQL大型数据库的智能问答系统优化
  • Emacs 多个方便查看函数列表的功能
  • QML QQuickImage: Cannot open: qrc:/images/shrink.png(已解决)
  • 前端-初识Vue实例
  • Spring Boot Redis序列化全解析(7种策略)
  • 2024年06月 Python(四级)真题解析#中国电子学会#全国青少年软件编程等级考试
  • leetcode 461 汉明距离
  • 如何在FastAPI中玩转全链路追踪,让分布式系统故障无处遁形?
  • 基于MCP工具的开发-部署-上线与维护全流程技术实现与应用研究
  • 北斗导航 | PPP-RTK算法核心原理与实现机制深度解析
  • AI助力PPT创作:秒出PPT与豆包AI谁更高效?
  • TypeScript:map和set函数
  • 【前端教程】从基础到专业:诗哩诗哩网HTML视频页面重构解析
  • Java试题-选择题(21)
  • new/delete 和 malloc/free 区别
  • 小杰机器视觉(five day)——直方图均衡化
  • linux系统学习(13.系统管理)
  • 基于orin系列的刷写支持笔记
  • 30分钟入门实战速成Cursor IDE(1)
  • 【拍摄学习记录】04-拍摄模式/曝光组合
  • Nginx的主要配置文件nginx.conf详细解读——及其不间断重启nginx服务等操作
  • 数据结构—第五章 树与二叉树
  • 机器学习算法全景解析:从理论到实践
  • vue3 鼠标移上去 显示勾选框 选中之后保持高亮
  • 自然语言提取PDF表格数据
  • 马斯克杀入AI编程!xAI新模型Grok Code Fast 1发布,深度评测:速度、价格与API上手指南
  • Vue3 + Spring Boot 项目中跨域问题的排查与解决
  • CS144 lab3 tcp_sender
  • 自动驾驶中的传感器技术36——Lidar(11)
  • 《生成式AI消费级应用Top 100——第五版》| a16z