在Postgres中,有没有办法在通过联结表链接的表之间执行left join
,并对链接表进行一些过滤?
说,我有两个表,humans
和pets
,我想执行查询,其中包含人员ID和宠物名称。如果人类ID存在,但他们没有带有该名称的宠物,我仍然希望返回人类的行。
如果我有pets
到humans
之间的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关系,我在humans
和pets
之间有一个联结表,所以我正在尝试查询: / p>
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行。< / p>
有没有办法复制FK样式left join
的行为,但是当与联结表一起使用时?
答案 0 :(得分:2)
一种方法是在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;
答案 1 :(得分: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;
可以在
JOIN
子句周围使用括号来控制连接顺序。 在没有括号的情况下,JOIN
条款从左到右嵌套。
我将谓词j.human_id = 13
添加到您的联结表和宠物之间的联接中,以尽早消除不相关的行。外LEFT JOIN
只需要虚拟条件ON TRUE
。
除了1:我假设你知道你有一个n:m(多对多)关系的教科书实现?
除了2:示例中的不幸命名约定使得必须处理列别名。不要使用&#34; id&#34;和&#34;名称&#34;作为实际表中的列名以避免此类冲突。使用适当的名称,如&#34; pet_id&#34;,&#34; human_id&#34;等