在 SQL 中,IN 語句和(hé) EXISTS 語句經常可(kě)以實現(xiàn)相(xiàng)✘±同的(de)查詢邏輯,但(dàn)執行(xíng)方式不(bù)同₩✔÷γ。IN 通(tōng)常用(yòng)于判斷某個(gè)值是(shì)否在★→♥&子(zǐ)查詢返回的(de)結果集中,而 EXISTS 則用(yòng)于判斷子(zǐ)查詢是(shì)否返回至少∞↓(shǎo)一(yī)條記錄(存在性判斷)。
下(xià)面通(tōng)過具體(tǐ)例子(zǐ)說(shuō)明(mín"↔£↓g)如(rú)何将 IN 語句用(yòng) EXISTS 語句替代。
場(chǎng)景說(shuō)明(míng)
假設有(yǒu)兩張表:
Orders(訂單表):包含order_id(訂單 ID)、user_id(用(yòng)戶 ID)等字段。Users(用(yòng)戶表):包含user_id(用(yòng)戶 ID)、country(國(guó)家(jiā))等字段。
需求:查詢所有(yǒu)「來(lái)自(zì)中國(guó)的(de)用(yò™∞&♣ng)戶」的(de)訂單信息。
用(yòng) IN 語句實現(xiàn)
sql
SELECT *
FROM Orders o
WHERE o.use®'r_id IN (
SELECT u.user_id
FROM Us÷×φers u
WHERE u.country = '中國(guó)' -- π←♦子(zǐ)查詢返回所有(yǒu)中國(guó)用(yòng)戶的(de)ID
);♣λδ
邏輯:先通(tōng)過子(zǐ)查詢獲取所有(yǒu)中國(guó)用(yòng↔α÷©)戶的(de) user_id,再判斷訂單表的(de) user_id 是(shì)否在這(zhè)個(gè)集合中。
用(yòng) EXISTS 語句實現(xiàn)(等價效果)
sql
SELECT *
FROM Orders o
WHERE EXISTS (₩¥
SELECT * -- EXISTS 隻關心是±λ(shì)否有(yǒu)記錄,SELECT 後的(de)內(&€nèi)容無意義
FROM Users u
WHERE u.cou☆♦ntry = '中國(guó)' -- 條件(jiàn)1:用(yòng)戶來(↑€₩lái)自(zì)中國(guó)
AND u.user_id = o.user_id ₹¶ -- 條件(jiàn)2:用(yòng)戶ID與當前訂單的(de)用¥¥'(yòng)戶ID匹配
);
邏輯:對(duì)于訂單表的(de)每一(yī)行(xíng)記錄(o),檢查是(shì)否存在一(yī)條用(yòng)戶表記錄(u),既滿足 “來(lái)自(zì)中國(guó)”,又(§♦≠yòu)滿足 “用(yòng)戶 ID 與當前訂單的(de)'♣用(yòng)戶 ID 相(xiàng)同”。如(rú)果存在,則保留該訂單記錄。
兩者的(de)核心等價性
IN是(shì) “值在集合中”:o.user_id是(shì)否在子(zǐ)查詢返回的(de)user_id集合中。EXISTS是(shì) “存在匹配記錄”:是(shì)否存在一♣♦♠(yī)條用(yòng)戶記錄,既符合子(zǐ)查詢條件(jiàn)(中國φ×<(guó)),又(yòu)與當前訂單關聯(user_id相(xiàng)等)。
兩種寫法最終會(huì)篩選出完全相(xiàng)同的(de)訂單記∑≤✘錄。
擴展:多(duō)值匹配的(de) IN 轉 EXISTS
如(rú)果 IN 子(zǐ)查詢返回多(duō)列(如(rú) (a, b)),EXISTS 同樣可(kě)以替代:
IN 寫法:
sql
SELECT * FROM TableA a WHERE (a.x, a.y) IN ( ÷¶ SELECT b.x, b.y FROM TableB b WHERE b∞↑β¶.status = 1 );

EXISTS 寫法:
sql
SELECT *
FROM TableA a
WHERE EXISTS (
SELEC↕>✘T *
FROM TableB b
WHE≠↓RE b.status = 1
AND b.x = a.x -- 多(du♣↑♦ō)字段匹配
AND b.y = a.y
);

總結
EXISTS 替代 IN 的(de)核心思路(lù)是(shì):
将 IN 子(zǐ)查詢的(de) “值集合判斷”,轉化(huà)σλ為(wèi) “是(shì)否存在一(yī)條與主查詢當前行(xíα₽ng)匹配且滿足條件(jiàn)的(de)子(zǐ)查詢記錄”,通(tōn×π♠✘g)過 主表與子(zǐ)表的(de)字段關聯(如(rú) u.user_id = o.user_id)實現(xiàn)等價過濾。