EXISTS 和 NOT EXISTS 、IN (和 NOT IN)

在 SQL 中,EXISTSNOT EXISTSIN 都是用于子查詢的條件運算符,用于根據子查詢的結果過濾主查詢的行。它們之間的區別主要體現在工作方式、效率、對 NULL 值的處理以及適用場景上。

1. EXISTS 和 NOT EXISTS

  • 作用:
    • EXISTS: 檢查子查詢是否至少返回一行。如果子查詢返回至少一行,則條件為 TRUE
    • NOT EXISTS: 檢查子查詢是否沒有返回任何行。如果子查詢返回零行,則條件為 TRUE
  • 工作方式 (關聯子查詢):
    • EXISTS/NOT EXISTS 通常與關聯子查詢一起使用。
    • 對于主查詢的每一行,數據庫引擎都會執行一次子查詢。
    • 子查詢的 WHERE 子句通常會引用主查詢當前行的列值(這就是“關聯”的含義)。
    • 數據庫引擎一旦在子查詢中找到一行匹配(對于 EXISTS) 或確認沒有匹配(對于 NOT EXISTS),就會停止執行該次子查詢,因為它只需要知道是否存在記錄,不需要知道具體有多少條或是什么內容。
  • 效率:
    • 當子查詢可能返回大量結果,但你只關心“是否存在”時,EXISTS/NOT EXISTS 通常效率更高
    • 原因在于它們利用了短路求值:找到第一個匹配項(EXISTS) 或確認沒有匹配項(NOT EXISTS) 后立即停止掃描子查詢的表。
    • 關聯條件(主表列 = 子查詢表列)通常能有效利用索引。
  • 對 NULL 的處理:
    • EXISTS/NOT EXISTS 只關心子查詢是否返回行。
    • 子查詢中的 NULL不影響判斷。只要子查詢能返回至少一行(即使該行所有列都是 NULL),EXISTS 就為 TRUE;只要子查詢返回零行,NOT EXISTS 就為 TRUE
  • 語法:
    SELECT column1, column2, ...
    FROM table_name_main main
    WHERE EXISTS (SELECT 1 -- 常用 SELECT 1, 實際返回什么值不重要,重要的是是否有行FROM table_name_sub subWHERE sub.correlated_column = main.correlated_column -- 關聯條件AND ... -- 其他子查詢條件
    );SELECT column1, column2, ...
    FROM table_name_main main
    WHERE NOT EXISTS (SELECT 1FROM table_name_sub subWHERE sub.correlated_column = main.correlated_column -- 關聯條件AND ... -- 其他子查詢條件
    );
    
  • 適用場景:
    • 檢查主表記錄在相關表中是否有對應記錄(存在性檢查)。
    • 檢查主表記錄在相關表中是否沒有對應記錄(缺失性檢查)。
    • 當子查詢邏輯依賴于主查詢的當前行時(必須使用關聯子查詢)。

示例:找出有訂單的客戶 (EXISTS)

SELECT CustomerID, CustomerName
FROM Customers c
WHERE EXISTS (SELECT 1FROM Orders oWHERE o.CustomerID = c.CustomerID -- 關聯條件:訂單的客戶ID = 當前客戶ID
);
  • Customers 表的每一行,檢查 Orders 表中是否有 CustomerID 匹配的訂單。只要有一條訂單,該客戶就會被選出。

示例:找出沒有訂單的客戶 (NOT EXISTS)

SELECT CustomerID, CustomerName
FROM Customers c
WHERE NOT EXISTS (SELECT 1FROM Orders oWHERE o.CustomerID = c.CustomerID -- 關聯條件
);
  • Customers 表的每一行,檢查 Orders 表中是否有 CustomerID 匹配的訂單。如果一條都沒有,該客戶就會被選出。

2. IN (和 NOT IN)

  • 作用:
    • IN: 檢查主查詢列的值是否等于子查詢返回結果集中的任何一個值
    • NOT IN: 檢查主查詢列的值是否不等于子查詢返回結果集中的所有值
  • 工作方式 (非關聯子查詢 - 通常):
    • IN/NOT IN 通常與非關聯子查詢一起使用(但也可以是關聯的,效率可能變差)。
    • 數據庫引擎會先完整執行一次子查詢,生成一個包含所有結果的中間結果集(值列表)
    • 然后,主查詢會檢查每行的指定列值是否存在于 (IN) 或不存在于 (NOT IN) 這個預先計算好的中間結果集中。
    • 這個過程類似于 WHERE column = value1 OR column = value2 OR ... (IN) 或 WHERE column <> value1 AND column <> value2 AND ... (NOT IN)。
  • 效率:
    • 當子查詢返回的結果集非常小時,IN 可能比較高效,尤其是主查詢列有索引且列表值不多時。
    • 當子查詢返回的結果集非常大時,IN 可能效率較低
      • 需要存儲整個中間結果集(可能消耗內存/臨時空間)。
      • 主查詢需要對這個龐大的列表進行查找(哈希或排序查找可能比索引查找慢)。
    • 如果 IN 子查詢是關聯的,效率通常不如 EXISTS,因為它需要為每一行重新生成或查找那個中間結果集。
  • 對 NULL 的處理 (重要陷阱!):
    • IN: 如果子查詢返回的結果集中包含 NULL,這本身不影響 IN 的判斷。value IN (1, 2, NULL) 等價于 value = 1 OR value = 2 OR value = NULLvalue = NULL 的結果是 UNKNOWN,但只要有 value=1value=2TRUE,整個條件就是 TRUE。如果 value 既不是 1 也不是 2,結果是 UNKNOWN(按 FALSE 處理)。
    • NOT IN: 對 NULL 值非常敏感! value NOT IN (1, 2, NULL) 等價于 value <> 1 AND value <> 2 AND value <> NULLvalue <> NULL 的結果總是 UNKNOWN。根據邏輯運算規則,TRUE AND UNKNOWN = UNKNOWNFALSE AND UNKNOWN = FALSEUNKNOWN AND UNKNOWN = UNKNOWN。所以,只要子查詢結果集中包含 NULL,整個 NOT IN 條件對于主查詢的任何行都會計算為 UNKNOWN(被當作 FALSE 處理),導致沒有行被返回!這是 NOT IN 的最大陷阱。
  • 語法:
    SELECT column1, column2, ...
    FROM table_name_main
    WHERE column_name_main [NOT] IN (SELECT single_column_name -- 子查詢必須只返回一列FROM table_name_sub[WHERE ...] -- 子查詢條件
    );
    
  • 適用場景:
    • 檢查主查詢列的值是否在一個明確的、較小的靜態值列表中(如 WHERE Country IN ('USA', 'UK', 'Canada'))。
    • 檢查主查詢列的值是否在一個獨立的、返回少量唯一值的子查詢結果集中。
    • 當子查詢邏輯不依賴于主查詢的當前行時(非關聯子查詢)。

示例:找出在特定國家的客戶 (IN)

SELECT CustomerID, CustomerName
FROM Customers
WHERE Country IN ('Germany', 'France', 'Spain'); -- 靜態值列表
SELECT CustomerID, CustomerName
FROM Customers
WHERE Country IN (SELECT DISTINCT SupplierCountry -- 獨立子查詢,返回少量國家FROM SuppliersWHERE SupplierName LIKE '%Gourmet%'
);

示例:NOT IN 的 NULL 陷阱演示
假設 SubTable 有一列 some_col,其中包含一行 NULL

SELECT *
FROM MainTable
WHERE main_col NOT IN (SELECT some_col FROM SubTable);
  • 如果 SubTablesome_col 包含 NULL,那么無論 main_col 的值是什么,這個查詢永遠不會返回任何行。因為 main_col NOT IN (..., NULL) 總是計算為 UNKNOWN (FALSE)。

關鍵區別總結

特性EXISTS / NOT EXISTSIN / NOT IN
核心目的檢查存在性 (是否有/沒有匹配行)檢查成員資格 (值是否在/不在列表中)
工作機制關聯子查詢為主。對主表每一行執行子查詢,找到/找不到即停。非關聯子查詢為主。先執行子查詢生成完整值列表,主查詢在列表中查找。
效率傾向通常更高效 (尤其子查詢大時),利用短路和關聯索引。小列表高效,大列表可能低效 (需存儲和查找大列表)。關聯子查詢效率差。
處理 NULL安全。只關心行是否存在,NULL 行不影響判斷。IN 安全NULL 在子查詢結果中不影響。 NOT IN 危險!子查詢結果含 NULL 會導致無結果 (整個條件變 UNKNOWN)。
子查詢列子查詢 SELECT 列表內容無關緊要 (常用 SELECT 1)。子查詢必須且只能返回一列
主要用途基于相關表的存在性/缺失性檢查。與靜態值列表或獨立小結果集進行值比較。

選擇建議

  1. 進行存在性/缺失性檢查時 (如“有訂單的客戶”、“沒訂單的產品”):
    • 首選 EXISTS (存在) 或 NOT EXISTS (缺失)。效率通常更高,語義更清晰,且完全避免 NOT INNULL 陷阱。
  2. 與小的、靜態的值列表比較時 (如 Country IN ('US', 'UK')):
    • 使用 IN 非常合適且直觀。
  3. 與一個獨立的、返回少量唯一值的子查詢結果比較時:
    • 可以使用 IN
    • 如果子查詢可能返回 NULL 并且你需要使用 NOT IN務必確保子查詢結果集排除 NULL (例如 WHERE NOT IN (SELECT col FROM ... WHERE col IS NOT NULL)),或者直接改用 NOT EXISTS 更安全。
  4. 避免 NOT IN 用于子查詢:
    • 強烈建議不要使用 NOT IN (SELECT ...),尤其是當子查詢結果集來源表可能包含 NULL 值時。總是優先用 NOT EXISTS 替代 NOT IN 用于子查詢場景。
  5. 關聯子查詢中的存在性檢查:
    • 必須使用 EXISTS/NOT EXISTSIN 雖然語法上可以寫成關聯的 (如 WHERE col IN (SELECT ... WHERE correlated_condition)),但其執行計劃通常不如 EXISTS 高效。

總結一句話:存在性檢查就用 EXISTS/NOT EXISTS;和小列表或獨立小結果集比較值就用 IN堅決避免用 NOT IN 檢查子查詢的結果,用 NOT EXISTS 代替。理解它們的工作機制和 NULL 陷阱對于寫出正確高效的 SQL 至關重要。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/86700.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/86700.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/86700.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

GitHub 趨勢日報 (2025年06月25日)

&#x1f4ca; 由 TrendForge 系統生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日報中的項目描述已自動翻譯為中文 &#x1f4c8; 今日獲星趨勢圖 今日獲星趨勢圖 880 awesome 788 build-your-own-x 691 free-for-dev 427 best-of-ml-python 404 …

互聯網大廠Java求職面試:Java虛擬線程實戰

互聯網大廠Java求職面試&#xff1a;Java虛擬線程實戰 文章內容 開篇&#xff1a;技術總監與程序員鄭薪苦的三輪對話 在一場緊張而嚴肅的Java工程師面試中&#xff0c;技術總監張工正對候選人鄭薪苦進行深入提問。鄭薪苦雖然性格幽默&#xff0c;但對技術有著扎實的理解。今天…

網絡安全的兩大威脅:XSS與CSRF攻擊實例解析

在網絡攻擊中,XSS跨站腳本攻擊(Cross Site Scripting)與CSRF跨站請求偽造攻擊(Cross-Site Request Forgery)是兩種常見的攻擊方式,它們之間存在顯著的區別。以下是對這兩種攻擊方式的詳細比較: 一、攻擊原理 XSS跨站腳本攻擊 攻擊者通過在Web頁面中注入惡意腳本來實現攻…

如何一次性將 iPhone 中的聯系人轉移到 PC

許多重要的聯系人都存儲在您的 iPhone 上。為了保護關鍵信息&#xff0c;您可能需要將聯系人從 iPhone 轉移到 PC&#xff0c;這是一種有效的聯系人備份方法。如果您在將 iPhone 聯系人轉移到電腦上遇到困難&#xff0c;現在可以從本文中學習 5 個有效的解決方案&#xff0c;然…

Spring Boot開啟定時任務的三種方式 【@EnableScheduling注解,SchedulingConfigurer接口,Quartz 框架】

Spring Boot 開啟定時任務的三種方式? ? ? 在 Spring Boot 應用開發過程中&#xff0c;定時任務是十分常見的需求&#xff0c;比如定時清理日志文件、定期備份數據庫數據、定時發送郵件提醒等。Spring Boot 提供了多種開啟定時任務的方式&#xff0c;本文將詳細介紹三種常見…

LLM 編碼器 怎么實現語義相關的 Token 向量更貼近? mask訓練:上下文存在 ;; 自回歸訓練:只有上文,生成模型

LLM 編碼器 怎么實現語義相關的 Token 向量更貼近? 目錄 LLM 編碼器 怎么實現語義相關的 Token 向量更貼近?mask訓練:上下文存在自回歸訓練:只有上文,生成模型一、核心機制:損失函數與反向傳播的“語義校準”1. 損失函數的“語義約束”2. 嵌入層參數的“動態調整”二、關…

從OCR瓶頸到結構化理解來有效提升RAG的效果

當人們探討如何讓人工智能系統更好地從文檔中查找和使用信息時&#xff0c;通常關注的是令人矚目的算法和前沿的大型語言模型。但問題是&#xff1a;如果文本提取的質量很差&#xff0c;那么后續的努力都將付諸東流。本文探討OCR質量如何影響檢索增強生成&#xff08;RAG&#…

SpringBoot -- 整合Junit

11.SpringBoot 整合 Junit 11.1 為什么需要單元測試 由于在SpringBoot開發過程中&#xff0c;每開發一個模塊&#xff0c;有時需要從 controller、service、mapper 到甚至 xml 文件的編寫全部開發完畢才能進行測試&#xff0c;這是十分浪費時間的&#xff0c;比如開發人員想測…

虛擬機遠程連接編譯部署QT程序

概要 邏輯 我們需要湊齊 QT庫、交叉編譯工具、sysroot這三大件。 交叉編譯的程序是部署到板卡環境運行,需要構建和板卡一樣的庫環境。 sysroot是我們在虛擬機上自己命名的一個文件夾,包含開發板的運行系統所需的所有文件。 虛擬機是x64版本,開發板是arm64版本。 如果開發板…

基于SpringBoot的智慧旅游系統

以智慧旅游系統的設計與實現為研究對象&#xff0c;旨在通過科技手段提升旅游業的管理效能和游客體驗。在系統設計方面&#xff0c;深入分析了地理特征、豐富的文化底蘊以及多樣的自然景觀。結合這些獨特之處&#xff0c;構建了一個多層次的旅游管理系統&#xff0c;包括景點信…

下載最新版本的OpenOCD

Download OpenOCD for Windowsd&#xff1a; https://gnutoolchains.com/arm-eabi/openocd/

Geollama 輔助筆記:raw_to_prompt_strings_geo.py

1 GeoLifePreprocessingDF 1.1 創造函數 1.2 讀取原始數據 讀取這個DataFrame 1.3 處理原始DataFrame 1.4 生成對應prompt 1.5 打亂軌跡 1.6 打亂軌跡里面的事件

TDengine 如何打破工業實時數據庫勢力邊界?

打破工業實時數據庫勢力邊界&#xff0c;TDengine 時序數據庫與工業 SCADA 深度融合 隨著 時序數據庫&#xff08;Time Series Database&#xff09;的日益普及&#xff0c;越來越多的工業自動化控制&#xff08;工控&#xff09;人員開始認識到其強大能力。然而&#xff0c;時…

滲透靶場:事件和屬性被阻止的反射xss

本關很多標簽被攔截了&#xff0c;需要使用 burp 模糊測試哪個標簽可以用 <a>和<animate>可以使用&#xff0c;<animate>是<svg>標簽中用來給動畫設定屬性的&#xff0c;看看<svg>可不可用 利用<svg>、<animate>、<a>來構造 這…

STM32中Usart的使用

目錄 一、USART簡介 1.電平標準 2.通信接口 3.硬件電路 4.串口參數以及時序 5.串口時序 二、USART結構介紹 1.USART功能框圖 ?編輯 1.1 功能引腳 1.2 數據寄存器 1.3 控制器 1.4 波特率發生器 1.5簡化結構圖 2.數據幀 一、USART簡介 USART&#xff08;Universa…

鴻蒙HarmonyOS 5小游戲實踐:數字記憶挑戰(附:源代碼)

數字記憶挑戰游戲&#xff1a;打造提升大腦記憶力的鴻蒙應用 在當今數字時代&#xff0c;人們的記憶力面臨著前所未有的挑戰。從日常的待辦事項到復雜的工作任務&#xff0c;強大的記憶力都是提高效率和表現的關鍵。本文將介紹一款基于鴻蒙系統開發的數字記憶挑戰游戲&#xf…

記錄一個C#/.NET的HTTP工具類

記錄一個C#/.NET的HTTP工具類 using Serilog; using System.Net; using System.Text; using System.Text.Json;namespace UProbe.Common.Comm.Http {public class HttpClientHelper{/// <summary>/// 發送HttpGet請求/// </summary>/// <typeparam name"T…

深度學習:PyTorch卷積神經網絡之圖像入門

本文目錄&#xff1a; 一、二值圖像二、**灰度圖像*三、**索引圖像**四、**真彩色RGB圖像****星空圖** 前言&#xff1a;這篇文章開始講解CNN&#xff0c;此前講解的人工神經網絡&#xff08;ANN&#xff09;如果有小伙伴還不清楚&#xff0c;一定要多看&#xff0c;多練習&…

PyTorch RNN實戰:快速上手教程

PyTorch實現RNN的實例 以下是一個使用PyTorch實現RNN的實例代碼,包含數據準備、模型定義、訓練和評估步驟。 RNN流程圖 RNN流程圖,在使用t來表示當前時間點(序列中的第t項),RNN接收所有先前內容得單一個表示h和關于序列最新項的信息,RNN將這些信息合并到迄今為止所有看…

C++項目快速配置SQLite

前言&#xff1a;完全沒接觸過數據庫&#xff0c;但老師課程設計要求數據存儲在數據庫怎么辦&#xff1f;&#xff1f;&#xff1f;主包看了些網絡上的資源&#xff0c;覺得講得都不是很能快速上手&#xff0c;所以決定自己寫一篇博客 SQLiteCpp是一個基于 C 封裝的 SQLite 操…