将行值转换为列名

Posted

技术标签:

【中文标题】将行值转换为列名【英文标题】:Transform Row Values to Column Names 【发布时间】:2020-10-07 15:57:47 【问题描述】:

我有一张客户联系人及其角色的表格。下面的简化示例。

customer | role        | userid
----------------------------
1        | Support     | 123
1        | Support     | 456
1        | Procurement | 567
...

想要的输出

customer | Support1 | Support2 | Support3 | Support4 | Procurement1 | Procurement2
-----------------------------------------------------------------------------------
1        | 123      | 456      | null     | null     | 567          | null
2        | 123      | 456      | 12333    | 45776    | 888          | 56723

因此,根据该角色的用户数量动态创建所需列的数量。这是少数角色。我也可以假设最多 5 个用户担任同一角色。这意味着最坏的情况我需要为每个角色生成 5 列。用户 ID 无需按任何特定顺序排列。

我目前的方法是为每个角色/客户获取 1 个用户 ID。然后第二个查询提取另一个不属于第一个结果集的 id。等等。但这样我必须静态创建 5 个查询。有用。但我想知道是否有更有效的方法?动态创建所需的列。

每个角色拉一个用户的示例:

SELECT customer,role,
(SELECT  top 1 userid
FROM temp as tmp1
where tmp1.customer=tmp2.customer and tmp1.role=tmp2.role
) as userid
 FROM temp as tmp2
 group by customer,role
 order by customer,role

使用虚拟数据创建 SQL

create table temp
    (
      customer int,
      role nvarchar(20),
      userid int
    )
    
    insert into temp values (1,'Support',123)
    insert into temp values (1,'Support',456)
    insert into temp values (1,'Procurement',567)
    insert into temp values (2,'Support',123)
    insert into temp values (2,'Support',456)
    insert into temp values (2,'Procurement',888)
    insert into temp values (2,'Support',12333)
    insert into temp values (2,'Support',45776)
    insert into temp values (2,'Procurement',56723)

【问题讨论】:

嗨,MS SQL Server。刚刚标记 【参考方案1】:

如果您想避免进入编程用户定义表函数的领域(这是动态生成列所需要的),您可能需要稍微调整您的方法。您没有提及您正在使用哪个 SQL 数据库变体(SQL Server、PostgreSQL、?)。我将假设它支持某种形式的字符串聚合功能(它们几乎都支持),但是这样做的语法会有所不同,因此您可能必须根据您的情况调整代码。您提到角色的数量很少(5-ish?)。建议的解决方案是使用公用表表达式 (CTE) 和 LISTAGG(在其他数据库中命名为 STRING_AGG、GROUP_CONCAT 等)函数生成一个以逗号分隔的用户 ID 列表,每个角色一个。

WITH tsupport 
     AS (SELECT customer, 
                Listagg(userid, ',') AS "Support" 
         FROM   temp 
         WHERE  ROLE = 'Support' 
         GROUP  BY customer), 
     tprocurement 
     AS (SELECT customer, 
                Listagg(userid, ',') AS "Procurement" 
         FROM   temp 
         WHERE  ROLE = 'Procurement' 
         GROUP  BY customer)
 --> tnextrole... 
 --> AS (SELECT ... for additional roles 
 -->            Listagg...
SELECT a.customer, 
       "Support", 
       "Procurement" 
 -->   "Next Role"  etc.
FROM   tsupport a 
       JOIN tprocurement b 
         ON a.customer = b.customer 
 -->   JOIN tNextRole ...

Fiddle 是 here,根据您的虚拟数据,结果如下所示:

【讨论】:

以上是关于将行值转换为列名的主要内容,如果未能解决你的问题,请参考以下文章

在 SQL Server 中将行值转换为列名

将行名转换为列名,并按日期求和并显示数据

如何动态地将行转换为列,并为每列使用不同的列名

动态生成列名时如何获取kendo选择的行值

查询结果作为嵌套查询中的列名

将行值转换为火花数据框中的列数组