I have table named 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 |
and I would like to convert it to the (First Conversion) below format which will sum Level2
and column group by Level1 ‘ as below
select Level1, level2, sum(level3) as level3 from table group by level2 order by level1
Then (Second Conversion) combining the common rows which had the same Level1
to be like below
Advertisement
Answer
You may consider grouping your data and using STRING_AGG
as shown below
Conversion 1
The code below groups by Level1
and Level2
and sums Level3
before renaming it to 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 |
Conversion 2
The query below uses the results from the previous query as a subquery (may also be used as a CTE if desired) and uses the STRING_AGG
function to concatenate the grouped results based on LEVEL1
. You may additionally order the results if desired.
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
Edit 1:
For SQL Server Versions not supporting STRING_AGG
, the following approach using JOINs and CROSS APPLY with FOR XML PATH
to Concatenate the columns may be used:
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
or simplier
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
Let me know if this works for you