Outer Join(外連接)
Outer join 保留配不到對象的列。它解的問題是內連接(INNER JOIN,也就是只寫 JOIN 時的預設)會讓沒有對應資料的那些列整個消失,而那些列常常正是要找的對象。產出的仍然是一個 relation,只是比來源表多了一些補 NULL 的列。
書店有三位顧客——佳穎下過兩張訂單、宗翰與雅文一張都沒下。要一份「每位顧客與他的訂單」的名單,用內連接得到:
1佳穎 101
2佳穎 102宗翰與雅文不在名單上。他們沒有訂單可以配對,於是內連接把他們整個丟掉了。換成 LEFT JOIN:
1佳穎 101
2佳穎 102
3宗翰 NULL
4雅文 NULL這就是「保護」的意思:左邊那張表的每一列都留著,右邊配不上的欄位補 NULL。而「哪些顧客一張單都沒下」這個問題,答案正是那兩列補 NULL 的——內連接會讓它無從回答。
三種寫法差在保護哪一側:LEFT 保護左運算元,RIGHT 保護右運算元,FULL 兩側都保護。
概念位置
外連接產出的仍然是一個 relation,所以它可以繼續當下一個連接的輸入,而 query optimizer 在特定條件下可以把它降級成內連接——前提是查詢的其他部分已經讓補 NULL 的那些列不可能出現在結果裡。
補上的 NULL 是這個機制的產物,與資料裡本來就有的空值來源不同。這一點決定了後續怎麼判斷:IS NULL 問的可能是「這一列沒配到」,也可能是「配到了而那個欄位本來就空」。
可觀察訊號與例子
保護會被 WHERE 抵銷。上面那個 LEFT JOIN 加上 WHERE 訂單.金額 > 100 之後,宗翰與雅文那兩列的金額是 NULL、答不出「大於 100」,於是被篩掉,結果與內連接相同。
外連接寫了卻拿到內連接的結果,多半就是這件事:WHERE 裡引用了右表的欄位。判斷保不保得住的方法是把補 NULL 的那一列代進條件裡:判成真才留得下來。IS NULL 判成真所以保住,IS NOT NULL 判成假所以取消——兩者看起來成對而落在相反的一側。而反查「沒配到的那些」要挑一個不可為空的欄位(通常是連接鍵)來問 IS NULL,用可為空的欄位會把「配到了而那個欄位本來就空」的列一起挑進來。
設計責任
要在保留左側全部列的前提下限制右側的配對範圍,條件寫進 ON;要從成品裡篩,條件寫進 WHERE。兩者在內連接底下同值,所以這個差別只在外連接現形。
鏈式查詢裡混用 LEFT 與 RIGHT 會讓保護的方向中途反轉。RIGHT 的右運算元通常只是一張表,而左運算元是前面累積出來的全部,所以保護範圍與多數人的本意相反。把需要保護的表移到最前面、其餘一律 LEFT,方向就一致了。