使用視圖關聯多表時,需求:左表所有資料必須顯示,右表僅顯示符合特定條件(如 years=2010)的資料,不符合則顯示 NULL。直接在 WHERE 子句過濾右表欄位會導致左連接退化為內連接,資料遺失。
SELECT *
FROM table1 AS a
LEFT JOIN table2 AS b ON a.tid = b.tid
WHERE a.parentid = '' AND b.years = 2010; -- 錯誤!b.years=NULL 的行被過濾掉
結果:b.years = 2010 在 WHERE 中評估為 UNKNOWN(因 NULL = 2010 為 UNKNOWN),導致左表無對應右表資料的行被排除,實際變成內連接。
SELECT *
FROM table1 AS a
LEFT JOIN table2 AS b ON a.tid = b.tid AND b.years = 2010 -- 正確!
WHERE a.parentid = '';
差異本質:
ON 條件決定如何關聯:右表先依條件過濾,再與左表關聯;無匹配則右表欄位補 NULLWHERE 條件決定最終保留哪些行:在關聯完成後過濾,NULL 值不通過任何比較運算子複雜條件或效能考量時,可先過濾右表再關聯:
SELECT *
FROM table1 AS a
LEFT JOIN (
SELECT * FROM table2 WHERE years = 2010
) AS b ON a.tid = b.tid
WHERE a.parentid = '';
此寫法語意最清晰、最易維護,且優化器通常能產生相同執行計畫。
左連接保左表,右表條件寫 ON 邊;
WHERE 只篩左表欄,右表條件別亂牽。
-- 對比兩種寫法的執行計畫與結果集行數
SET STATISTICS IO ON;
SET STATISTICS TIME ON;
-- 寫法 A:WHERE 過濾右表
SELECT COUNT(*) FROM table1 a LEFT JOIN table2 b ON a.tid=b.tid WHERE b.years=2010;
-- 寫法 B:ON 過濾右表
SELECT COUNT(*) FROM table1 a LEFT JOIN table2 b ON a.tid=b.tid AND b.years=2010;