Sql-server – T-SQL Splitting rows into multiple rows

sql servert-sql

I have a unique request here. I have to split rows for each ID into separate rows, but moving sets of columns into separate rows. Kind of hard to explain with just that so here is a visual representation:

I have to get something like this:

            Column A    |   Column B    |   Column C    |   Column D
    ------------------------------------------------------------
    1       123         |    1abc       |     def       |      ghi
    ------------------------------------------------------------
    2       123         |    2abc       |     def       |      ghi
    ------------------------------------------------------------
    3       123         |    3abc       |     def       |      ghi
    ------------------------------------------------------------
    4       456         |    1abc       |     def       |      ghi
    ------------------------------------------------------------
    5       456         |    2abc       |     def       |      ghi

To look like this:

            Column A    |   Column B    |   Column C    |   Column D
    ---------------------------------------------------------------------
    1       123         |               |               |      
    ---------------------------------------------------------------------
    2                   |    1abc       |               |      
    ---------------------------------------------------------------------
    3                   |    2abc       |               |      
    ---------------------------------------------------------------------
    3                   |    3abc       |               |      
    ---------------------------------------------------------------------
    4                   |               |     def       |      
    ---------------------------------------------------------------------
    5                   |               |               |      ghi
    ---------------------------------------------------------------------
    6       456         |               |               |      
    ---------------------------------------------------------------------
    7                   |    1abc       |               |      
    ---------------------------------------------------------------------
    8                   |    2abc       |               |      
    ---------------------------------------------------------------------
    9                   |               |     def       |      
    ---------------------------------------------------------------------
    10                  |               |               |      ghi

I have a slight understanding that I will have to loop through the recordset then possibly use a CTE. This would then move onto the next ID in Column A and on.

Any ideas would be appreciated!

Best Answer

WITH cte AS (
SELECT *, DENSE_RANK() OVER (ORDER BY ColumnA) dr
FROM source
),
cte2 AS (
SELECT DISTINCT ColumnA, NULL ColumnB, NULL ColumnC, NULL ColumnD, dr
FROM cte
UNION ALL
SELECT DISTINCT NULL, ColumnB, NULL, NULL, dr
FROM cte
UNION ALL
SELECT DISTINCT NULL , NULL, ColumnC, NULL, dr
FROM cte
UNION ALL
SELECT DISTINCT NULL, NULL, NULL, ColumnD, dr
FROM cte
)
SELECT ColumnA, ColumnB, ColumnC, ColumnD 
FROM cte2
ORDER BY dr, ColumnA DESC, ColumnB DESC, ColumnC DESC, ColumnD DESC

fiddle

PS. Edit final ORDER BY clause (except dr first) as you need.