【问题标题】:Convert table data and reformat转换表格数据并重新格式化
【发布时间】:2021-08-23 22:44:16
【问题描述】:

我有一个名为Table的表

id Level1 Level2 Level3
1 US CA 13000
2 FR PA 30000
3 US CA 24000
4 US LA 10000
5 UK LN 500
6 UK LN 600
7 FR PA 888
8 FR DF 1000

我想将其转换为以下格式(第一次转换),该格式将 Level2 和列组按 Level1 ' 如下所示

select Level1, level2, sum(level3) as level3
from table
group by level2
order by level1

然后(第二次转换)将具有相同Level1 的公共行合并为如下所示

【问题讨论】:

  • 根据问题指南,请不要发布代码、数据、错误消息等的图像 - 将文本复制或键入问题中。请保留将图像用于图表或演示渲染错误,无法通过文本准确描述的事情。

标签: sql sql-server tsql pivot


【解决方案1】:

您可以考虑将数据分组并使用STRING_AGG,如下所示

转化 1

下面的代码按Level1Level2 分组,并在重命名为LEVEL3 之前对Level3 求和

SELECT
    Level1,
    Level2,
    SUM(Level3) as Level3
FROM
    my_table
GROUP BY
    Level1,
    Level2;
Level1 Level2 Level3
US CA 37000
FR PA 30888
US LA 10000
UK LN 1100
FR DF 1000

转化 2

下面的查询使用上一个查询的结果作为子查询(如果需要,也可以用作 CTE)并使用STRING_AGG 函数连接基于LEVEL1 的分组结果。如果需要,您可以另外订购结果。

    
SELECT
    Level1,
    STRING_AGG(Level2,',') as Level2,
    STRING_AGG(Level3,',') as Level3
FROM (
    SELECT
        Level1,
        Level2,
        SUM(Level3) as Level3
    FROM
        my_table
    GROUP BY
        Level1,
        Level2
) t
GROUP BY
    Level1
Level1 Level2 Level3
FR PA,DF 30888,1000
UK LN 1100
US CA,LA 37000,10000

Working example on db-fiddle here

编辑 1:

对于不支持 STRING_AGG 的 SQL Server 版本,可以使用以下方法使用 JOIN 和 CROSS APPLY 与 FOR XML PATH 来连接列:

WITH group_1 as (
    SELECT
        Level1,
        Level2,
        CONVERT(VARCHAR(10),SUM(Level3)) as Level3
    FROM
        my_table
    GROUP BY
        Level1,
        Level2
),
level2_grouped AS (
    SELECT
        Level1,
        LEFT(MergedValues,LEN(MergedValues)-1) AS Level2
    FROM group_1 extern
    CROSS APPLY (
        SELECT
            Level2+','
        FROM
            group_1 intern
        WHERE
            extern.Level1 = intern.Level1
        FOR XML PATH('')
    )merged(MergedValues)
),
level3_grouped AS (
    SELECT
        Level1,
        LEFT(MergedValues,LEN(MergedValues)-1) AS Level3
    FROM group_1 extern
    CROSS APPLY (
        SELECT
            Level3+','
        FROM
            group_1 intern
        WHERE
            extern.Level1 = intern.Level1
        FOR XML PATH('')
    )merged(MergedValues)
)
SELECT
    g1.Level1,
    l2.Level2,
    l3.Level3
FROM 
    group_1 g1
INNER JOIN 
    level2_grouped l2 ON g1.Level1 = l2.Level1
INNER JOIN 
    level3_grouped l3 ON g1.Level1 = l3.Level1
GROUP BY
    g1.Level1,
    l2.Level2,
    l3.Level3

或者更简单

WITH group_1 as (
    SELECT
        Level1,
        Level2,
        CONVERT(VARCHAR(10),SUM(Level3)) as Level3
    FROM
        my_table
    GROUP BY
        Level1,
        Level2
),
level_grouped AS (
    SELECT
        Level1,
        LEFT(Merged2Values,LEN(Merged2Values)-1) AS Level2,
        LEFT(Merged3Values,LEN(Merged3Values)-1) AS Level3
    FROM group_1 extern
    CROSS APPLY (
        SELECT
            Level2+','
        FROM
            group_1 intern
        WHERE
            extern.Level1 = intern.Level1
        FOR XML PATH('')
    )merged2(Merged2Values)
    CROSS APPLY (
        SELECT
            Level3+','
        FROM
            group_1 intern
        WHERE
            extern.Level1 = intern.Level1
        FOR XML PATH('')
    )merged3(Merged3Values)
)
SELECT
    Level1,
    Level2,
    Level3
FROM 
    level_grouped g1
GROUP BY
    Level1,
    Level2,
    Level3

Working db fiddle

让我知道这是否适合你

【讨论】:

  • 非常感谢,它运行良好,但适用于 MSSQL 2017 及更高版本。我的数据库版本是 2012 。
  • @tamersalem 我在答案的编辑中添加了另一种方法。让我知道这是否适合您。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-12
  • 1970-01-01
  • 2019-02-01
  • 2014-09-03
  • 1970-01-01
相关资源
最近更新 更多