2015-02-23 155 views
2

在Postgres中,有沒有辦法在連接表連接的表之間執行left join,並在鏈接表上進行一些過濾?在三個表中使用左連接(使用連接表)

說,我有兩個表,humanspets,我想執行一個查詢,我有人的ID和寵物的名字。如果人的身份證存在,但他們沒有這個名字的寵物,我仍然希望人的行被退回。

如果我不得不從petshumans一個FK關係,這會工作:

select h.*, p.* 
from humans as h 
left join pets as p on p.human_id = h.id and p.name = 'fluffy' 
where h.id = 13 

,我會得到一排人13的詳細信息,以及蓬鬆的價值觀。另外,如果人類13沒有一隻叫做'蓬鬆'的寵物,我會得到一排人13的值,以及寵物列的空值。

,我並沒有直接的關係FK,我有humanspets之間的結合表,所以我想喜歡的查詢:

select h.*, p.* 
from humans as h 
left join humans_pets_junction as j on j.human_id = h.id 
left join pets as p on j.pet_id = p.id and p.name = 'fluffy' 
where h.id = 13 

它爲所有的返回行人類13的寵物,除了蓬鬆的排外,還有空的柱子。

如果我將p.name = 'fluffy'添加到WHERE子句中,該子句將過濾掉所有空行,但也意味着如果人13沒有根本沒有名爲絨毛的寵物,則會獲得0行。

有沒有辦法複製FK風格left join的行爲,但是與聯結表一起使用?

+0

您的意思是在第二個查詢中選擇h。*,p。*',對嗎? – 2015-02-24 00:02:49

+0

我冒昧解決了推定的錯字。 – 2015-02-24 01:01:35

回答

1

一種方法是做where子句中的比較:

select h.*, p.* 
from humans as h left join 
    humans_pets_junction as j 
    on j.human_id = h.id left join 
    pets as p 
    on j.pet_id = p.id and p.name = 'fluffy' 
where h.id = 13 and (p.name = 'fluffy' or p.id is null); 

另外,加入結表和寵物表作爲一個子查詢或CTE:

select h.*, p.* 
from humans h left join 
    (select j.* 
     from humans_pets_junction j join 
      pets p 
      on j.pet_id = p.id and p.name = 'fluffy' 
    ) pj 
    on pj.human_id = h.id 
where h.id = 13; 
+0

第一個查詢有一個內置的陷阱,可用於'pets.name'可以爲null的設置。 'LEFT JOIN'後面的'p.name爲null' *表達式不能告訴人類沒有寵物名稱缺失情況下的關聯寵物(空)。使用'..或p.id爲空)'來修復。沒有缺點。而且,兩個查詢都從問題中複製無效參考'r。*'。 – 2015-02-24 00:54:12

+0

@ErwinBrandstetter。 。 。確實如此。我將它改爲'id'。 – 2015-02-24 01:00:46

+0

感謝您的回答。我更喜歡第一種形式,但似乎無法讓它與上面的外鍵示例類似(也就是說,如果人類13沒有名爲「蓬鬆」的寵物,現在行被返回,而不是與人列和沒有寵物列的行)。但子查詢表單起作用。 – Jordan0Day 2015-02-24 15:33:08

1

在Postgres裏,你可以使用括號優先JOIN訂單。你並不需要一個子查詢:

SELECT h.*, p.id AS p_id, p.name AS pet_name 
FROM humans h 
LEFT JOIN (pets p 
     JOIN humans_pets_junction j ON p.name = 'fluffy' 
            AND j.pet_id = p.id 
            AND j.human_id = 13) ON TRUE 
WHERE h.id = 13;

Per documentation:

括號可以圍繞JOIN條款來控制連接順序。 在沒有括號的情況下,JOIN子句從左到右嵌套。

我將謂詞j.human_id = 13添加到聯結表和寵物之間的聯接中,以儘早消除不相關的行。外部LEFT JOIN只需要虛擬條件ON TRUE

SQL Fiddle.

除了1:我想大家都知道,你有一本教科書實施的n:M(許多一對多)的關係?

除了2:本例中的不幸的命名慣例使我們有必要處理了列別名。不要在實際表中使用「id」和「name」作爲列名以避免這種衝突。使用諸如「pet_id」,「human_id」等專用名稱。