在LEFT JOIN中防止重复值

Gau*_*mal 18 sql join

我遇到了一个我从中得到重复值的情况LEFT JOIN.我认为这可能是一种理想的行为,但与我想要的不同.

我有三个表:person,departmentcontact.

人:

id bigint,
person_name character varying(255)
Run Code Online (Sandbox Code Playgroud)

部门 :

person_id bigint,
department_name character varying(255)
Run Code Online (Sandbox Code Playgroud)

联系 :

person_id bigint,
phone_number character varying(255)
Run Code Online (Sandbox Code Playgroud)

Sql查询:

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;
Run Code Online (Sandbox Code Playgroud)

结果:

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"
Run Code Online (Sandbox Code Playgroud)

我知道这是联接做的事情,保持与选定的行相乘.但它给像电话号码从某种意义上说023451,99478,67890是两个部门,而他们只与人约翰不必要的重复值,这将有更大的数据集升级的问题.
所以,这就是我想要的:

id|person_name|department_name|phone_number
--+-----------+---------------+------------
1 |"John"     |"Finance"      |"023451"
1 |"John"     |"Marketing"    |"99478"
1 |"John"     |""             |"67890"
2 |"Barbara"  |"Finance"      |""
3 |"Michelle" |""             |"005634"
Run Code Online (Sandbox Code Playgroud)

这是我的情况的一个示例,我正在使用大量的表和查询.所以,需要一个通用的解决方案.

Erw*_*ter 15

我喜欢称这个问题为"通过代理交叉加入".由于没有信息(WHEREJOIN条件)表如何departmentcontact通过代理表应该投其所好,他们是交叉连接person-让您的笛卡尔乘积.与此非常相似:

那里有更多解释.

查询解决方案:

SELECT p.id, p.person_name, d.department_name, c.phone_number
FROM   person p
LEFT   JOIN (
  SELECT person_id, min(department_name) AS department_name
  FROM   department
  GROUP  BY person_id
  ) d ON d.person_id = p.id
LEFT   JOIN (
  SELECT person_id, min(phone_number) AS phone_number
  FROM   contact
  GROUP  BY person_id
  ) c ON c.person_id = p.id;
Run Code Online (Sandbox Code Playgroud)

你没有定义接部门或电话号码,让我随意选择了第一.你可以用任何其他方式......


ale*_*ods 6

我认为您只需要获取特定人员的部门和电话列表。所以只需使用array_agg(或string_aggjson_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
Run Code Online (Sandbox Code Playgroud)