問題:一方關聯多方查詢時執行否定篩選,結果包含未通過篩選的項。
我們規定一方為父,多方為子,我們希望子未通過篩選時,結果也不出現對應的父。
查詢部門及部門下的所有員工。
SELECT * FROM department LEFT JOIN employee ON department.id = employee.did;
查詢不是員工Tom所在的部門及部門下的所有員工。
第一想法是:SELECT * FROM department LEFT JOIN employee ON department.id = employee.did WHERE employee.name != 'Tom';
但是結果如下,結果仍包含部門 1 ,當mybatis等處理結果時,就會為部門 1 建立例項。這不是我們想要的。
解決1:not in 的思想(這個很慢,直接看解決2)
not in 的思想是:先查出條件句的肯定,然後外部用not in篩選。
這裡就是,先找出有員工Tom的部門,然後篩選不是這個部門的所有部門及員工。
SELECT * FROM department LEFT JOIN employee ON department.id = employee.did WHERE department.id
NOT IN (SELECT department.id FROM department LEFT JOIN employee ON department.id = employee.did WHERE employee.name = 'Tom');
NOT IN 篩選ID的時候使用最後一個一方的ID,會更快一點。
例如:A 多對一 B 一對一 C 多對一 D 多對多 E
這個時候一直到 D 都是一方 所以 NOT IN 時使用 D 的欄位篩選。即...WHERE D.COLUMN NOT IN (SELECT D.COLUMN FROM...
解決2:not in 的思想進階
使用LEFT JOIN 代替 NOT IN。
將NOT IN 的子查詢當做一個表,對其進行關聯,然後篩選這個表欄位為空的。
例如還是這個例子
SELECT department.id FROM department LEFT JOIN employee ON department.id = employee.did WHERE employee.name = 'Tom';
我們設這個表為 nodepartment 列為 id。結果應該只有一行一列 ‘1’。
則主表關聯nodepartment後 department.id 為 2 的行 nodepartment.id這一列為null。所以主表條件 nodepartment.id IS NULL就可以了。
在這裡就是:
SELECT * FROM department LEFT JOIN employee ON department.id = employee.did
LEFT JOIN
(SELECT department.id AS nodepid FROM department LEFT JOIN employee ON department.id = employee.did
WHERE employee.name = 'Tom') AS nodep ON department.id = nodep.nodepid
WHERE nodepid IS NULL;