如何展平 SQL 查询的结果 - 将行转换为列?

Posted

技术标签:

【中文标题】如何展平 SQL 查询的结果 - 将行转换为列?【英文标题】:How Can I Flatten the Results of a SQL Query - Transposing Rows to Columns? 【发布时间】:2021-01-27 15:20:42 【问题描述】:

我有一张桌子,我想加入其他一些桌子。名为“OfficePers”的表有一个字段表示办公室位置 ID,还有一个字段表示在该位置工作的人员的 ID,另一个字段表示他们的姓名。例如,表格的格式如下:

| OfficeLocation | PersonID |
|--------------  | -------- |    
|321             |   2323   |   
|321             |   2355   |   
|321             |   1234   |   
|321             |   7899   |   
|321             |   32091  |   
|321             |   777    |       
|1654            |   4232   |   
|121243          |   345    |       
|121243          |   343    |       
|121243          |   111    |   

我想要做的是创建一个子查询,它为每个办公地点返回一个结果,并为每个 personID 和 name 创建别名 - 因此上表将转换为如下所示:

| OfficeLocation |  PersonID_1 | PersonID_2 | PersonID_3 | PersonID_4| PersonID_5| PersonID_6|
| -------------- | ----------- |----------- |----------- |-----------|-----------|-----------|
| 321            |      2323   |    2355    |   1234     |  7899     |  32091    |  777      |
| 1654           |      4232   |            |            |           |           |           |
| 121243         |       345   |    343     |    111     |           |           |           |

 

我正在考虑做一些事情,比如多次加入“OfficePers”表,但我不确定我可以使用什么函数来解析每个人 ID - 我熟悉使用 Max 和 Min 但是这不适用于在同一位置拥有超过 2 个 Person ID 的情况。

【问题讨论】:

您事先知道每个办公室的最大人数吗?如果不是,您是否可以每个办公室最多显示六个(即使对于可能有 20 人的办公室)?在同一个办公室的 20 个人中,你如何选择展示哪六个?即使对于六人或更少人的办公室,你如何决定谁在第一列,谁在第二列,等等? (如果“没关系,任何顺序都可以”,这是一个有效的答案,但不要让我们猜测这就是答案。) 【参考方案1】:

最简单的方法是使用listagg() 将它们组合成一列:

select OfficeLocation,
       listagg(personid, ',') within group (order by personid) as personids
from t
group by OfficeLocation;

出于多种原因,我不建议将值放在单独的列中。首先,您不知道需要多少列。其次,您可以使用动态 SQL 执行此操作,但不能为结果创建视图。第三,理论上,同一个人可能会出现在多行中,但该人可能会出现在不同的列中。

编辑:

如果你想要正好六列,你可以使用条件聚合:

select OfficeLocation,
       max(case when seqnum = 1 then PersonId) as PersonId_1,
       max(case when seqnum = 2 then PersonId) as PersonId_2,
       max(case when seqnum = 3 then PersonId) as PersonId_3,
       max(case when seqnum = 4 then PersonId) as PersonId_4,
       max(case when seqnum = 5 then PersonId) as PersonId_5,
       max(case when seqnum = 6 then PersonId) as PersonId_6
from (select t.*,
             row_number() over (partition by OfficeLocation order by personid) as seqnum
      from t
     ) t
group by OfficeLocation;

【讨论】:

谢谢 Gordon - 问题是,查询的结果正在输入一个表单。因此,在表单上有 6 个单独的部分,我将在其中放置 Person_1 的信息,然后在一个单独的部分中放置 Person_2 的信息等。最多我需要 6 列 - 我应该在前面提到过。 将它与***.com/questions/5199849/… 结合起来,你就在那里。对于较短的行,您可能需要一些案例 @Jonathan 。 . .如果你知道你需要六列,那么条件聚合是合适的。 @GordonLinoff - 这就像一个宝石 - 非常感谢!

以上是关于如何展平 SQL 查询的结果 - 将行转换为列?的主要内容,如果未能解决你的问题,请参考以下文章

使用可能的组合将行转换为列

将行转换为列的 MS SQL 连接查询

SQL Server 将行数据转换为列标题

使用可能的组合将行转换为列

Oracle SQL Developer:如何使用 PIVOT 函数将行转置为列

在 SQL 中使用“Pivot”将行转换为列