🔍 WHERE 子句中使用子查询:深度解析与最佳实践

WHERE 子句中使用子查询是 SQL 的高阶技巧,可实现动态条件过滤。以下是全面指南,涵盖语法、类型、陷阱及优化策略:


📜 一、基础语法结构

SELECTFROM 主表 
WHERE 列 操作符 (SELECT 子查询);

🧩 二、三种核心类型

1. 标量子查询(单行单列)
-- 查询工资高于平均工资的员工
SELECT name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees  -- 返回单个值
);-- 可搭配比较运算符:=, >, <, >=, <=, <>
2. 行子查询(单行多列)
-- 查找与特定员工职位+部门相同的员工
SELECT name, job, dept
FROM employees
WHERE (job, dept) = (SELECT job, dept FROM employees WHERE id = 101  -- 返回单行多列
);
3. 集合子查询(多行单列)
-- 查询有订单的客户
SELECT name 
FROM customers
WHERE id IN (SELECT DISTINCT cust_id FROM orders  -- 返回多行单列
);-- 常用操作符:IN, NOT IN, ANY, ALL, EXISTS

⚠️ 三、六大关键注意事项

1. NULL 值的致命陷阱
-- ❌ 危险:NOT IN 遇 NULL 返回空结果
SELECT name 
FROM products
WHERE id NOT IN (SELECT product_id FROM discontinued  -- 若子查询含 NULL
);-- ✅ 解决方案:显式过滤 NULL
SELECT name 
FROM products
WHERE id NOT IN (SELECT product_id FROM discontinued WHERE product_id IS NOT NULL  -- 关键!
);
2. 子查询返回结果数量
-- ❌ 错误:标量子查询返回多行
SELECT name 
FROM employees
WHERE salary = (SELECT MAX(salary) FROM employees GROUP BY dept  -- 多行!
);-- ✅ 修正:确保返回单行
WHERE salary IN (SELECT ...)  -- 改用 IN
3. 性能黑洞(关联子查询)
-- ❌ 低效:每行执行一次子查询(O(n²))
SELECT name, salary
FROM employees e
WHERE salary > (SELECT AVG(salary) FROM employees WHERE dept = e.dept  -- 关联子查询
);-- ✅ 优化:先聚合再连接
WITH dept_avg AS (SELECT dept, AVG(salary) avg_salFROM employees GROUP BY dept
)
SELECT e.name, e.salary
FROM employees e
JOIN dept_avg d ON e.dept = d.dept
WHERE e.salary > d.avg_sal;
4. 索引失效场景
-- ❌ 子查询中对列使用函数
WHERE id IN (SELECT UPPER(product_code) FROM products  -- 索引失效!
)-- ✅ 优化:主查询预处理
WHERE UPPER(id) IN (SELECT product_code FROM products)
5. EXISTS vs IN 的选择
场景推荐原因
子查询结果集小IN解析更快
子查询结果集大EXISTS短路执行,不加载全部结果
需要处理 NULLEXISTS天然避免 NOT IN NULL 陷阱
关联子查询EXISTS通常更高效
-- EXISTS 示例(检查存在订单)
SELECT name
FROM customers c
WHERE EXISTS (SELECT 1 FROM orders o   -- 不返回数据,只检查存在性WHERE o.cust_id = c.id   -- 关联条件
);
6. 同名字段歧义
-- ❌ 错误:主查询与子查询同名冲突
SELECT id, name
FROM employees
WHERE dept_id IN (SELECT id FROM depts WHERE name = 'IT'  -- 哪个 id?
);-- ✅ 方案:显式别名限定
SELECT e.id, e.name
FROM employees e
WHERE e.dept_id IN (SELECT d.id FROM depts d WHERE d.name = 'IT'
);

🚀 四、性能优化策略

1. 子查询转为连接
-- 原始子查询
SELECT * 
FROM products p
WHERE p.category_id IN (SELECT id FROM categories WHERE type = 'ELECTRONIC'
);-- ✅ 优化为 JOIN
SELECT p.*
FROM products p
JOIN categories c ON p.category_id = c.id
WHERE c.type = 'ELECTRONIC';
2. 限制子查询返回列
-- ❌ 低效:返回所有列
WHERE id IN (SELECT * FROM ...)-- ✅ 高效:只返回必要列
WHERE id IN (SELECT id FROM ...)
3. 临时表物化
-- 复杂子查询先存为临时表
CREATE TEMPORARY TABLE temp_ids AS
SELECT id FROM large_table WHERE condition;-- 主查询使用临时表
SELECT * 
FROM main_table 
WHERE id IN (SELECT id FROM temp_ids);

🔧 五、高级用法示例

1. 多层嵌套子查询
-- 找出销售额超过部门平均的产品
SELECT product_name
FROM sales s
WHERE amount > (SELECT AVG(amount)FROM sales WHERE dept_id = (SELECT dept_id FROM products WHERE id = s.product_id)
);
2. ANY/ALL 运算符
-- 工资高于IT部门任意员工的销售
SELECT name 
FROM sales_emps
WHERE salary > ANY (SELECT salary FROM it_emps
);-- 工资高于IT部门所有员工
WHERE salary > ALL (SELECT ...)
3. 条件组合
-- 多条件子查询
SELECT *
FROM orders
WHERE cust_id IN (SELECT id FROM vip_customers)AND product_id NOT IN (SELECT id FROM discontinued_products);

💎 终极使用指南

场景推荐方案替代方案
简单值过滤标量子查询变量/JOIN
检查记录是否存在EXISTSJOIN ... WHERE NULL
多值匹配IN + 非关联子查询JOIN
关联条件过滤关联子查询先聚合再连接
复杂逻辑判断CASE + 子查询应用层处理

📌 黄金法则

  1. 优先用 EXISTS 替代 IN(尤其 NOT EXISTS vs NOT IN
  2. 子查询中绝对避免 SELECT *
  3. 超过 3 层嵌套考虑重构为 CTE 或临时表
  4. EXPLAIN 分析执行计划,关注 DEPENDENT SUBQUERY 警告

性能警示标志

-- 执行计划中出现 ↓ 表示性能风险
+----+--------------------+--------+------+...
| id | select_type        | table  | type |
+----+--------------------+--------+------+
| 1  | PRIMARY            | e      | ALL  |
| 2  | DEPENDENT SUBQUERY | dept   | ALL  |  -- 关联子查询全表扫!
+----+--------------------+--------+------+

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/86824.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/86824.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/86824.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从0到1:不文明现象随手拍小程序开发日记(一)

前期调研 不文明现象随手拍小程序&#xff1a;在城市的快速发展进程中&#xff0c;不文明现象时有发生&#xff0c;为了有效解决这一问题&#xff0c;提升城市文明程度&#xff0c; 市民若发现不文明行为&#xff0c;如乱扔垃圾、随地吐痰、破坏公共设施、违规停车等&#xff…

STM32F103之SPI软件读写W25Q64

一、W25Q64简介 1.1 简介 W25Q64(Nor flash)、 24位地址&#xff0c;64Mbit/8MByte、是一种低成本、小型化、使用简单的非易失性存储器&#xff0c;常用于数据存储、字库存储、固件程序存储等场景 时钟频率&#xff1a;最大80MHz(STM32F103系统时钟为72MHz…

vue3+element-plus 组件功能实现 上传功能

一、整体功能概述 这段代码实现了一个基于 Vue 3 和 Element Plus 组件库的文件导入及预览功能模块。主要包含了一个主导入对话框&#xff08;用于上传文件、展示文件相关信息、进行导入操作等&#xff09;以及一个用于预览文件内容的预览对话框。支持导入特定格式&#xff08;…

OpenCV中创建Mat对象

第1章 创建Mat对象 1.1. 创建空的 Mat 对象 cv::Mat mat; 1.2. 创建灰度图像 // 创建一个 3 行 4 列、8位无符号单通道矩阵&#xff08;相当于灰度图&#xff09; cv::Mat mat(3, 4, CV_8UC1); 1.3. 创建彩色图像 // 创建三通道矩阵&#xff08;相当于彩色图像&#xff0…

10、做中学 | 五年级下期 Golang循环控制

一、一个小需求 我想要打印10遍hello world,你想怎么编写呢&#xff1f; // 需求&#xff1a;打印10遍"hello world"fmt.Println("hello world")fmt.Println("hello world")fmt.Println("hello world")fmt.Println("hello world…

机器学习算法-K近邻算法-KNN

1. K近邻算法是什么&#xff1f; 定义&#xff1a; K近邻是一种基于实例的懒惰学习&#xff08;Lazy Learning&#xff09;算法&#xff0c;用于分类和回归任务。 核心思想&#xff1a;“物以类聚”——通过计算样本间的距离&#xff0c;找到目标点的最近K个邻居&#xff0c;…

基于vue框架的法律知识咨询普及系统gwuv7(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,知识类型,律师,律师推荐,法律知识,新闻类型,法律新闻,咨询律师 开题报告内容 基于Vue框架的法律知识咨询普及系统开题报告 一、研究背景与意义 随着法治社会建设的深入推进&#xff0c;公众对法律知识的需求呈现爆发式增长。然而…

Netty 揭秘CompositeByteBuf:零拷贝优化核心技术

CompositeByteBuf 类 核心设计目标​​ ​​虚拟缓冲区​​&#xff1a;将多个 ByteBuf 合并为单一逻辑视图&#xff0c;减少数据复制。​​零拷贝优化​​&#xff1a;通过组合而非复制提升性能。​​引用计数管理​​&#xff1a;统一管理底层 ByteBuf 的生命周期。 核心成…

用css实现文字字体颜色渐变

用css实现文字字体颜色渐变 background-clip 是CSS3中新增的属性&#xff0c;可以用于指定背景图片或颜色的绘制范围。利用 background-clip 属性实现文字颜色从左到右、从绿到白的渐变效果&#xff1a; 代码如下&#xff1a; .gradient-color {background-image: linear-gr…

SpringBatch处理数据性能优化

SpringBatch的Step默认使用同步方式批量处理数据&#xff0c;也可以通过配置将读数改为同步&#xff0c;处理和写入改为异步方式。 1、同步处理Step SpringBatch的Step一般由ItemReader、ItemProcessor和ItemWriter组成&#xff0c;其中ItemProcessor是可选的。他的设计思路的…

【机器学习深度学习】前馈神经网络(单隐藏层)

目录 一、什么是前馈神经网络&#xff1f; 二、数学表达式是什么&#xff1f; 三、为什么需要“非线性函数”&#xff1f; 四、NumPy 实现前馈神经网络代码示例 五、 运行结果 六、代码解析 6.1 初始化部分 6.2 前向传播 6.3 计算损失&#xff08;Loss&#xff09; 6…

设计模式系列(08):创建型模式 - 原型模式

系列导读&#xff1a;完成创建型模式的学习&#xff0c;我们来看最后一个创建型模式——原型模式。它通过复制已有对象来创建新对象&#xff0c;是一种独特的创建方式。 解决什么问题&#xff1a;通过复制现有对象来创建新对象&#xff0c;而不是重新实例化。适用于对象创建成本…

区块链到底是什么?

区块链本质上是一种去中心化的分布式账本技术&#xff0c;具有以下核心特点&#xff1a; - 去中心化&#xff1a;没有中央管理机构&#xff0c;数据由网络中的多个节点共同维护&#xff0c;比如比特币网络中各个节点都保存着完整账本。 - 分布式存储&#xff1a;数据不是存在一…

系统架构设计师论文分享-论ATAM的使用

我的软考历程 摘要 2023年2月&#xff0c;我司通过了研发纱线MES系统的立项&#xff0c;该系统为国内纱线工厂提供SAAS服务&#xff0c;旨在提高纱线工厂的数字化和智能化水平。我在本项目中担任系统架构设计师&#xff0c;负责整个项目的架构设计工作。本文结合我在该项目中…

vue-28(服务器端渲染(SSR)简介及其优势)

服务器端渲染&#xff08;SSR&#xff09;简介及其优势 服务器端渲染&#xff08;SSR&#xff09;是现代网络应用的关键技术&#xff0c;特别是使用 Vue.js 等框架构建的应用。它通过在服务器上渲染初始应用状态来弥补传统单页应用&#xff08;SPA&#xff09;的局限性&#x…

工业电子 | 什么是SerDes,为何工业和汽车应用需要它?

重点内容速览&#xff1a; 1. 什么是SerDes&#xff1f; 2. ADI&#xff1a;私有协议的GMSL将向公有协议转变 3. TI&#xff1a;工业和汽车有两套SerDes解决方案 4. Microchip&#xff1a;推出通用协议SerDes芯片 5. 罗姆&#xff1a;主要针对汽车领域 6. 国产SerDes芯…

大事件项目记录4-用户接口开发-更新用户基本信息

4&#xff09;更新用户基本信息。 UserController.java&#xff1a; UserMapper.java&#xff1a; Update("update user set nickname #{nickname},email #{email},update_time #{updateTime} where id #{id}")void update(User user); UserServiceInterface…

Transformer结构--输入编码(BPE,PE)

在Transformer结构中&#xff0c;输入编码是模型处理文本数据的关键步骤&#xff0c;其中**BPE&#xff08;Byte Pair Encoding&#xff0c;字节对编码&#xff09;和PE&#xff08;Positional Encoding&#xff0c;位置编码&#xff09;**是两种重要的编码方式&#xff0c;它们…

Confluence-测试用例设计指导方法

测试经验知识库 典型的测试场景验证点各个项目有价值的经验和测试点 测试经验知识库 - 草稿测试用例执行量化指导建议 何时需要进行全量测试和如何定义和执行测试用例量的一些建议和标准 端对端&#xff08;E2E&#xff09;测试用例设计指导方案 在测试行业中&#xff0c;端到端…

浅析JVM

一、JVM运行流程 如图&#xff1a; JVM由四个部分构成&#xff1a; 1.类加载器 加载类文件到内存2.运行时数据区 写的程序需要加载到这里才能运行3.执行引擎 负责解释命令&#xff0c;提交操作系统执行4.本地接口 融合不同编程语言为java所用&#xff0c;如Java程序驱动打印…