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

Posted

技术标签:

【中文标题】使一对多关系看起来像一对一【英文标题】:Make one-to-many relationship look like one-to-one 【发布时间】:2014-08-13 13:33:57 【问题描述】:

我正在使用 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】:

您需要交叉制表(有时称为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>

非常和这个相关案例很相似(有特殊困难的说明):

Postgres - Transpose Rows to Columns

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

另外,根据您的评论,您需要所有部门,即使没有分配任何人。相应地调整了 LEFT JOIN。

此相关答案中的基本细节:

PostgreSQL Crosstab Query

【讨论】:

感谢 Erwin,非常接近我正在寻找的输出 - 缺少 HR 的 NULL 行以及 first_name 和 last_name 的单独列。 @CodeBuddy:我反转了LEFT JOIN 以包括空部门并简化了查询。分开的名字,也可以解决。在外部查询中分解。 再次感谢,但新查询对我返回错误:错误:d.department_id 列不存在 @CodeBuddy: 显然是d.id(在我自己的设计中,我从不使用“id”或“name”等非描述性词语作为标识符。)

以上是关于使一对多关系看起来像一对一的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 GraphQL 创建一对多关系?

Laravel 5.8 在数据透视表上保存一对多关系

如何扁平化一对多的关系

如何保持对象一对多 RestKit

如何在 Laravel Eloquent 中构建具有多级关系的查询

MySQL 一对多到 JSON 格式