news 2026/8/12 21:23:11

主题:SQL 中 NOT EXISTS 的原理与最佳实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
主题:SQL 中 NOT EXISTS 的原理与最佳实践

两个sql,在某些情况下执行结果是一样的(not in如果子查询为null,可以直接报错)

---未上报的企业 select oewrt.id, oewrt.COUNTY_ID, oewrt.ENT_NAME, oewrt.LINKMAN, oewrt.PHONE from OIL_ENTER_WHSLEWHSE_RECORD_TAB oewrt where id not in (select oewrt.id from OIL_ENTER_MONTH_REPORT oemr left outer join OIL_ENTER_WHSLEWHSE_RECORD_TAB oewrt ON oewrt.id = oemr.RECORD_ID AND oemr.MONTH = :MONTH where oewrt.COUNTY_ID like substr(:countyId, 1, 2) || '%' and oewrt.ENT_TYPE IN (:ENT_TYPE, '3') AND oewrt.CONFIRM_STATUS = '2') and oewrt.COUNTY_ID like substr(:countyId, 1, 2) || '%' and oewrt.ENT_TYPE IN (:ENT_TYPE, '3') AND oewrt.CONFIRM_STATUS = '2';

而not exists更加安全,为什么?

SELECT oewrt.id, oewrt.COUNTY_ID, oewrt.ENT_NAME, oewrt.LINKMAN, oewrt.PHONE FROM OIL_ENTER_WHSLEWHSE_RECORD_TAB oewrt WHERE NOT EXISTS ( SELECT 1 FROM OIL_ENTER_MONTH_REPORT oemr WHERE oemr.RECORD_ID = oewrt.id AND oemr.MONTH = :MONTH ) and oewrt.COUNTY_ID LIKE SUBSTR(:countyId, 1, 2) || '%' AND oewrt.ENT_TYPE IN (:ENT_TYPE, '3') AND oewrt.CONFIRM_STATUS = '2';

❓ 你可能在想:

“如果子查询只写SELECT 1,那数据库怎么知道该排除主表中的哪一行?它连要比较的字段都没返回啊!”

答案是:比较字段不在SELECT里,而在WHERE里!


✅ 核心原理:关联条件在WHERE,不在SELECT

看这个经典写法:

SELECT * FROM customers c WHERE NOT EXISTS ( SELECT 1 -- ← 这里只表示“有结果就行” FROM orders o WHERE o.customer_id = c.id -- ← 关键在这里!建立关联 AND o.month = '202506' );

🔍 执行过程(对主表每一行):

  1. 拿到当前客户c.id = 1001
  2. 执行子查询:
    SELECT 1 FROM orders WHERE customer_id = 1001 AND month = '202506'
  3. 数据库去orders表里找:
    • 有没有一行满足customer_id = 1001month = '202506'
  4. 如果→ 子查询返回至少一行 →NOT EXISTS = false不选这个客户
  5. 如果没有→ 子查询返回空 →NOT EXISTS = true选中这个客户

🎯关键:关联字段c.ido.customer_id是通过WHERE o.customer_id = c.id建立的,和SELECT 1完全无关!


🧠 类比理解

想象你在查“没交作业的学生”:

  • 主表:全班学生名单(张三、李四、王五)
  • 子表:作业提交记录(张三、李四)

你不需要从作业记录里“返回学生名字”来对比,而是这样操作:

对每个学生,去作业记录里“按名字查找”

  • 能找到 → 交了 → 排除
  • 找不到 → 没交 → 保留

这里的“按名字查找”就是WHERE o.customer_id = c.id
SELECT 1只是回答:“找到了吗?(是/否)”


❌ 为什么你会觉得“需要返回字段”?

可能是因为混淆了以下两种模式:

模式写法依赖返回值?
集合排除WHERE id NOT IN (SELECT customer_id FROM ...)✅ 需要子查询返回具体值
存在性检查WHERE NOT EXISTS (SELECT 1 FROM ... WHERE 关联条件)❌ 不需要返回值,只看是否有行
  • NOT IN确实需要子查询返回一个值列表,然后主查询用这个列表做排除。
  • NOT EXISTS完全不依赖返回值,它只关心子查询是否能“找到匹配行”。
📌关键词 / 线索区(Cue Column)
  • NOT EXISTSvsNOT IN
  • 存在性检查(Existence Check)
  • 关联条件位置
  • 为什么用SELECT 1
  • NULL 安全性
  • 执行逻辑:逐行验证
  • 性能与可读性

📖主笔记区(Notes)

1. 核心思想
NOT EXISTS不是通过“返回字段值”来排除数据,而是对主表每一行,在子表中检查是否存在匹配记录。只要子查询返回 ≥1 行,EXISTS = true;否则为false

2. 关联靠WHERE,不靠SELECT

  • 关键关联写在子查询的WHERE中,例如:
    WHERE oemr.RECORD_ID = oewrt.id AND oemr.MONTH = :MONTH
  • SELECT 1只是一个占位符,表示“只关心是否有结果”,不参与逻辑判断。

3. 为什么用SELECT 1

  • ✅ 语义清晰:表明仅做存在性检查
  • ✅ 性能略优:避免读取实际列数据(尤其在旧数据库)
  • ✅ 行业惯例:被广泛接受的最佳实践

4.NOT EXISTSvsNOT IN

对比项NOT EXISTSNOT IN
工作方式逐行验证是否存在排除一个值列表
NULL 安全✅ 安全(不受影响)❌ 危险(含 NULL 则结果为空)
性能通常更快(可短路)可能全表扫描
可读性逻辑清晰易误解

5. 执行过程(伪代码)

for each row in 主表: if 子查询(带当前行的关联值) 返回 ≥1 行: 跳过(不满足 NOT EXISTS) else: 保留该行

6. 典型应用场景

  • 查询“未下单的客户”
  • 查找“未提交月报的企业”
  • 检测“缺少某类记录的数据”

🔚总结区(Summary)

NOT EXISTS是 SQL 中进行“不存在”判断的安全、高效、清晰的方式。它通过在子查询的WHERE子句中建立与主表的关联,逐行验证是否存在匹配记录,而SELECT 1仅作为存在性信号,不参与实际筛选。相比NOT IN,它天然规避了 NULL 带来的逻辑陷阱,是生产环境中推荐的标准写法。

💡口诀
关联写在 WHERE 里,SELECT 1 只问有没有;
逐行验证最可靠,NULL 再也不犯愁。


建议行动

  • 在今后写“未上报”“未完成”“无记录”类查询时,优先使用NOT EXISTS + SELECT 1
  • 避免在可能含 NULL 的场景使用NOT IN
  • 为子表的关联字段(如RECORD_ID, MONTH)建立复合索引以提升性能
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/12 19:43:42

【光伏风电功率预测】基于图神经网络的区域风光功率预测:场站“互相影响”怎么建模?

关键词:图神经网络GNN、区域风光功率预测、风电功率预测、光伏功率预测、场站相关性、时空预测、图注意力GAT、STGCN、DCRNN、Graph WaveNet、Transformer、Informer、多源气象融合、概率预测、P10/P50/P90、虚拟电厂、风光基地、聚合预测、偏差考核、现货交易1. 为…

作者头像 李华
网站建设 2026/8/12 17:45:13

手机号查QQ号终极指南:3步快速找回关联账号

手机号查QQ号终极指南:3步快速找回关联账号 【免费下载链接】phone2qq 项目地址: https://gitcode.com/gh_mirrors/ph/phone2qq 你是否曾经因为忘记QQ号而无法登录?或者需要确认某个手机号是否绑定过QQ账号?现在,通过phon…

作者头像 李华
网站建设 2026/8/12 14:20:22

Windows终端插件系统完全实战:从美化到效率提升的终极指南

Windows终端插件系统完全实战:从美化到效率提升的终极指南 【免费下载链接】terminal The new Windows Terminal and the original Windows console host, all in the same place! 项目地址: https://gitcode.com/GitHub_Trending/term/terminal 你是否还在忍…

作者头像 李华
网站建设 2026/8/11 4:12:58

软著是什么?一张“技术身份证”,为你的发展加速!

1. 简单来说 软著,全称“计算机软件著作权”,是你为自己开发的软件作品依法办的一张“法律身份证”。2. 权利内涵 它代表你对软件享有发表权、署名权、使用权、许可权和获得报酬等一系列专有权利,是知识产权的重要组成部分。3. 涵盖范围 无论…

作者头像 李华
网站建设 2026/8/11 11:32:50

终极指南:掌握PyQt-Fluent-Widgets滚动区域的高效应用技巧

终极指南:掌握PyQt-Fluent-Widgets滚动区域的高效应用技巧 【免费下载链接】PyQt-Fluent-Widgets A fluent design widgets library based on C Qt/PyQt/PySide. Make Qt Great Again. 项目地址: https://gitcode.com/gh_mirrors/py/PyQt-Fluent-Widgets PyQ…

作者头像 李华
网站建设 2026/8/11 16:42:37

掌握LosslessCut字幕处理的实用技巧

你是不是也遇到过这样的烦恼?下载的视频没有字幕,或者字幕跟音频完全对不上,看着画面里的人物张嘴说话,字幕却迟迟不来,那种抓狂的感觉真是让人崩溃 😫 【免费下载链接】lossless-cut The swiss army knife…

作者头像 李华