转换 table 数据并重新格式化

Convert table data and reformat

我有 table 名为 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 的公共行组合成如下所示

您可以考虑对数据进行分组并使用 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 服务器版本,可以使用以下使用 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

让我知道这是否适合你