將一個 SELECT 嵌入另一個查詢,將結果集比較邏輯下推至資料庫引擎,避免應用層撈回大量資料再比對,提升效能與簡潔度。
-- 找出 Metallica 專輯中歌詞包含 'justice' 的歌曲
SELECT song_name FROM Album
WHERE band_name = 'Metallica'
AND song_name IN (
SELECT song_name FROM Lyric
WHERE song_lyric LIKE '%justice%'
);
Album,內層 Lyric 提供歌曲名單集合。IN 子查詢結果集作為外層 WHERE 篩選條件。Lyric 欄位,僅作為條件來源。-- 找出 'And Justice for All' 專輯中歌詞「不含」 justice 的歌曲
SELECT song_name FROM Album
WHERE album_name = 'And Justice for All'
AND band_name = 'Metallica'
AND song_name NOT IN (
SELECT song_name FROM Lyric
WHERE song_lyric LIKE '%justice%'
);
NULL,NOT IN 將回傳空集合,建議改用 NOT EXISTS。-- 找出 Metallica 原唱且被 Damage, Inc. 翻唱的歌曲
SELECT Album.song_name FROM Album
WHERE Album.band_name = 'Metallica'
AND EXISTS (
SELECT 1 FROM Cover
WHERE Cover.band_name = 'Damage, Inc.'
AND Cover.song_name = Album.song_name
);
EXISTS 只檢查 是否至少存在一列,不回傳實際資料,效能通常優於 IN (尤其內層大量資料時)。Album.song_name),每列外層資料各執行一次內層查詢。Album.song_name, Cover.song_name) 避免歧義。-- 找出專輯實際收錄曲數與資料庫記錄曲數不符的專輯
SELECT AlbumInfo.album_name FROM AlbumInfo
WHERE AlbumInfo.band_name = 'Metallica'
AND AlbumInfo.album_tracks <> (
SELECT COUNT(*) FROM Album
WHERE Album.band_name = AlbumInfo.band_name
AND Album.album_name = AlbumInfo.album_name
);
COUNT(*) 計算實際歌曲數,與外層中繼資料欄位 album_tracks 比對。| 建議 | 理由 |
|---|---|
優先使用 EXISTS 代替 IN (大量內層資料) | EXISTS 可短路停止掃描,IN 需完整建立結果集 |
避免 NOT IN 含 NULL 風險 | 改用 NOT EXISTS 或 LEFT JOIN ... WHERE right.key IS NULL |
| 相關子查詢確保內層有索引支援 | 如 Cover(song_name, band_name) 複合索引 |
| 可轉為 JOIN 重寫時優先考慮 | 現代優化器常能自動轉換,但明確 JOIN 更易閱讀維護 |