萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

SQL EXISTS 子查詢詳解:存在性判斷邏輯與實戰範例

EXISTS 核心語意

EXISTS (subquery) 回傳 Boolean:若子查詢至少回傳一列則為 TRUE,否則 FALSE。不關心具體欄位值,只關心「有沒有行」。

等價邏輯:EXISTS (SELECT 1 FROM ... WHERE ...) —— SELECT 1、SELECT *、SELECT primary_key 效能相同,優化器會忽略選取清單。

範例資料結構

CREATE TABLE Student (
    StudentID INT PRIMARY KEY,
    Name VARCHAR(50) NOT NULL
);

CREATE TABLE Exam (
    ExamID INT PRIMARY KEY,
    CourseID INT, ProfessorID INT, SustainedOn DATE
);

CREATE TABLE StudentExam (
    StudentID INT, ExamID INT, Mark INT, IfPassed SMALLINT,
    FOREIGN KEY (StudentID) REFERENCES Student(StudentID),
    FOREIGN KEY (ExamID) REFERENCES Exam(ExamID)
);
-- 範例資料略(含 6 位學生、多筆考試與成績)

實戰查詢:找出「至少有一科不及格(< 40 分)」的學生

SELECT StudentID, Name
FROM Student s
WHERE EXISTS (
    SELECT 1
    FROM StudentExam e
    WHERE e.StudentID = s.StudentID
      AND e.Mark < 40
);

執行邏輯逐步拆解

  1. 外層逐列掃描 Student 表
  2. 對每位學生,執行子查詢:在 StudentExam 中找 StudentID 相符且 Mark < 40 的列
  3. 若子查詢找到任一列,EXISTS 為真,該學生被選出
  4. 子查詢短路:找到第一筆即停止,不掃描剩餘資料

EXISTS vs IN vs JOIN 效能對比

寫法適用場景效能特性
EXISTS外表大、內表小、需短路外層驅動,內層用索引求值,找到即停
IN子查詢結果集小、可物化MySQL 8.0+ 會轉為 Semi-Join,效能接近 EXISTS
JOIN需輸出內表欄位、或雙向過濾可能產生重複列,需 DISTINCT,成本較高

一般經驗法則:「存在性判斷用 EXISTS,資料關聯輸出用 JOIN」。

NOT EXISTS:反向邏輯

-- 找出「所有科目都及格」的學生(沒有任何一科 < 40)
SELECT StudentID, Name
FROM Student s
WHERE NOT EXISTS (
    SELECT 1 FROM StudentExam e
    WHERE e.StudentID = s.StudentID AND e.Mark < 40
);

進階用法:關聯子查詢中的多條件

-- 找出「參加過 CourseID=1 且 分數 > 80」的學生
SELECT s.Name
FROM Student s
WHERE EXISTS (
    SELECT 1
    FROM StudentExam se
    JOIN Exam ex ON se.ExamID = ex.ExamID
    WHERE se.StudentID = s.StudentID
      AND ex.CourseID = 1
      AND se.Mark > 80
);

優化建議

  1. 子查詢 WHERE 條件加索引:StudentExam(StudentID, Mark) 複合索引可大幅加速
  2. 避免 SELECT *:雖優化器會忽略,但習慣寫 SELECT 1 更清晰
  3. 大表用 EXISTS,小表用 IN:MySQL 8.0 優化器會自動轉換,但明確語意更好維護
  4. NOT EXISTS 防 NULL 陷阱:子查詢回傳含 NULL 的列時,NOT IN 會失效,NOT EXISTS 安全

總結

EXISTS 是 SQL 中表達「存在性」最語意清晰、效能最穩定的工具。掌握 相關子查詢 + 短路特性 + 索引配合,即可寫出高效能的存在性判斷查詢。

copyright © 萬盛學電腦網 all rights reserved