使一对多关系看起来像一对一

时间:2014-08-13 13:33:57

标签: sql postgresql

我正在使用postgres 9.3.5。

鉴于以下数据:

select * from department;
 id |   name    
----+-----------
  1 | sales
  2 | marketing
  3 | HR

select * from people;
 id | department_id | first_name | last_name 
----+---------------+------------+-----------
  1 |             1 | Tom        | Jones
  2 |             1 | Bill       | Cosby
  3 |             2 | Jessica    | Biel
  4 |             1 | Rachel     | Hunter
  5 |             2 | John       | Barnes

我想返回这样的结果集:

 id |   name    | first_name-1 | last_name-1 | first_name-2 | last_name-2 | first_name-3 | last_name-3
----+-----------+--------------+-------------+--------------+-------------+--------------+------------ 
  1 | sales     | Tom          | Jones       | Bill         | Cosby       | Rachel       | Hunter
  2 | marketing | Jessica      | Biel        | John         | Barnes
  3 | HR        |

这可能吗?

Max Shawabkeh使用GROUP_CONCAT提供的答案here已关闭 - 但它不会作为数据集中的额外字段返回,而是将它们连接成一个字段。

1 个答案:

答案 0 :(得分:1)

您需要交叉制表(有时称为 pivot )。

在你的情况下看起来像这样:

SELECT * FROM crosstab(
       $$SELECT d.id, d.name,'p' AS dummy_cat 
               ,concat_ws(' ', p.first_name, p.last_name) AS person
         FROM   department  d
         LEFT   JOIN people p ON p.department_id = d.id
         ORDER  BY d.department_id, p.id$$
       )
AS ct (id int, department text, person_1 text, person_2 text, person_3 text);

返回:

id  department  person_1      person_2     person_3
--------------------------------------------------------
1   sales       Tom Jones     Bill Cosby   Rachel Hunter
2   marketing   Jessica Biel  John Barnes  <NULL>
3   HR          <NULL>        <NULL>       <NULL>

非常类似于此相关案例(对特殊困难的解释):

但是这种情况更简单:因为您似乎并不关心列出人员的顺序,您可以使用crosstab()的基本单参数形式。

另外,根据您的评论,您希望所有部门,即使没有人员被分配。相应地调整了LEFT JOIN。

此相关答案的基本详情: