抽獎系統:enet_wall_list 記錄所有參與用戶(同一用戶可能多條),enet_wall_lottery 記錄中獎用戶。需求:**找出所有未中獎用戶(去重)**。
SELECT DISTINCT l.openid FROM `enet_wall_list` AS l LEFT JOIN `enet_wall_lottery` AS lottery ON l.openid = lottery.openid WHERE l.weid = 63 AND lottery.id IS NULL;
l)為基準,右表(lottery)匹配成功則帶入欄位,**匹配失敗則所有右表欄位填 NULL**。SELECT a.* FROM `A` a LEFT JOIN `B` b ON a.pid = b.pid WHERE b.pid IS NULL AND LENGTH(a.pid) < 10; -- 額外業務過濾
LEFT JOIN ... ON:左表全保留,右表無匹配則 NULL。WHERE b.key IS NULL:精準過濾「右表無對應」的行。LENGTH(str):計算字串長度(位元組),可用於過濾異常資料。| 方法 | SQL 範例 | 優點 | 缺點 |
|---|---|---|---|
| LEFT JOIN + IS NULL | 如上 | 標準 SQL、可攜性強、可直接選左表任意欄位 | 大表需注意索引 |
| NOT EXISTS | SELECT * FROM A WHERE NOT EXISTS (SELECT 1 FROM B WHERE B.pid=A.pid) | 語意清晰、優化器常能轉為 Anti-Join、不產生中間結果集 | 舊版 MySQL 優化較弱 |
| NOT IN | SELECT * FROM A WHERE pid NOT IN (SELECT pid FROM B) | 簡潔 | **子查詢含 NULL 會導致全表掃描且結果為空**,極度不推薦 |
| EXCEPT (MINUS) | SELECT pid FROM A EXCEPT SELECT pid FROM B | 集合運算語意明確 | MySQL **不支援** EXCEPT(MariaDB 10.3+ 支援) |
ALTER TABLE A ADD INDEX idx_pid (pid); ALTER TABLE B ADD INDEX idx_pid (pid);pid,單欄索引即為覆蓋索引,避免回表。WHERE A.weid=63 應有索引 idx_weid (weid) 或複合 idx_weid_pid (weid, pid)。SELECT a.* FROM `A` a LEFT JOIN `B` b ON a.col1 = b.col1 AND a.col2 = b.col2 WHERE b.col1 IS NULL;
複合連接條件同理,右表任一關鍵欄位為 NULL 即表示無匹配。
掌握 LEFT JOIN + IS NULL 模式,是處理「存在性否定」查詢的標準利器,配合正確索引可支撐千萬級資料量秒級回應。