我遇到了LEFT JOIN
重复值的情况。我认为这可能是一种理想的行为,但与我想要的不同。
我有三个表: person
, department
和 contact
。
人:
id bigint,
person_name character varying(255)
部门:
person_id bigint,
department_name character varying(255)
联系方式:
person_id bigint,
phone_number character varying(255)
Sql Query:
SELECT p.id, p.person_name, d.department_name, c.phone_number
FROM person p
LEFT JOIN department d
ON p.id = d.person_id
LEFT JOIN contact c
ON p.id = c.person_id;
结果:
id|person_name|department_name|phone_number
--+-----------+---------------+------------
1 |"John" |"Finance" |"023451"
1 |"John" |"Finance" |"99478"
1 |"John" |"Finance" |"67890"
1 |"John" |"Marketing" |"023451"
1 |"John" |"Marketing" |"99478"
1 |"John" |"Marketing" |"67890"
2 |"Barbara" |"Finance" |""
3 |"Michelle" |"" |"005634"
我知道这是联接所做的事情,保持与所选行相乘。但它给出的感觉就像电话号码023451
,99478
,67890
适用于两个部门,而它们只与人员john有关,其中包含不必要的重复值,这会使更大的数据集升级问题。
所以,这就是我想要的:
id|person_name|department_name|phone_number
--+-----------+---------------+------------
1 |"John" |"Finance" |"023451"
1 |"John" |"Marketing" |"99478"
1 |"John" |"" |"67890"
2 |"Barbara" |"Finance" |""
3 |"Michelle" |"" |"005634"
这是我的情况的一个示例,我正在使用大量的表和查询。所以,需要一种通用的解决方案。
答案 0 :(得分:12)
我喜欢将此问题称为“通过代理交叉加入”。由于没有信息(WHERE
或JOIN
条件)表department
和contact
如何匹配,因此它们通过代理表{{交叉连接1}} - 给你Cartesian product。与此非常相似:
那里有更多解释。
您的查询解决方案:
person
您没有定义要选择的部门或电话号码,因此我随意选择第一个。你可以用任何其他方式......
答案 1 :(得分:2)
我认为您只需要获取特定人员的部门和电话列表。所以只需使用array_agg
(或string_agg
或json_agg
):
SELECT
p.id,
p.person_name,
array_agg(d.department_name) as "department_names",
array_agg(c.phone_number) as "phone_numbers"
FROM person AS p
LEFT JOIN department AS d ON p.id = d.person_id
LEFT JOIN contact AS c on p.id = c.person_id
GROUP BY p.id, p.person_name
答案 2 :(得分:1)
虽然表格显然已经简化讨论,但看起来它们在结构上存在缺陷。表的结构应该显示实体之间的关系,而不仅仅是实体和/或属性的列表。在这种情况下,我会将电话号码视为(个人或部门实体)的属性。
第一步是创建具有关系的表,每个表都有一个主键,可能还有一个外键。在此示例中,让person表使用person_id作为主键,department表使用department_id作为其主键会很有帮助。接下来查看一对多或多对多关系,并相应地设置外键:
总而言之,您的方案中应该只有两个表:一个表用于人员,另一个表用于部门。即使允许个人电话号码(人员表中的列)和部门表中的部门编号,这也是更好的方法。
唯一需要注意的是,一个部门有多个号码(或多个部门共用一个电话号码),但这超出了原始问题的范围。
答案 3 :(得分:0)
使用此类查询: SQL Server
(您可以将id
的{{1}}更改为您想要的每个列
ORDER BY id
答案 4 :(得分:0)
SELECT p.id, p.person_name, d.department_name, c.phone_number
FROM person p
LEFT JOIN department d
ON p.id = d.person_id
LEFT JOIN contact c
ON p.id = c.person_id
group by p.id, p.person_name, d.department_name, c.phone_number