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 位學生、多筆考試與成績)
SELECT StudentID, Name
FROM Student s
WHERE EXISTS (
SELECT 1
FROM StudentExam e
WHERE e.StudentID = s.StudentID
AND e.Mark < 40
);
Student 表StudentExam 中找 StudentID 相符且 Mark < 40 的列EXISTS 為真,該學生被選出| 寫法 | 適用場景 | 效能特性 |
|---|---|---|
EXISTS | 外表大、內表小、需短路 | 外層驅動,內層用索引求值,找到即停 |
IN | 子查詢結果集小、可物化 | MySQL 8.0+ 會轉為 Semi-Join,效能接近 EXISTS |
JOIN | 需輸出內表欄位、或雙向過濾 | 可能產生重複列,需 DISTINCT,成本較高 |
一般經驗法則:「存在性判斷用 EXISTS,資料關聯輸出用 JOIN」。
-- 找出「所有科目都及格」的學生(沒有任何一科 < 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
);
StudentExam(StudentID, Mark) 複合索引可大幅加速SELECT 1 更清晰NULL 的列時,NOT IN 會失效,NOT EXISTS 安全EXISTS 是 SQL 中表達「存在性」最語意清晰、效能最穩定的工具。掌握 相關子查詢 + 短路特性 + 索引配合,即可寫出高效能的存在性判斷查詢。