One problem is that you need another column which returns the order of the values within the "col1", right now, there's no way to determine that, so i'm using @@SPID as sort, but it might not work in real scenarios. If you have some date or ID which can be used, you should replace the @@SPID with it.
The solution:
SELECT col1
, MAX(CASE WHEN type = 2 THEN v END) col2
, MAX(CASE WHEN type = 3 THEN v END) col3
, MAX(CASE WHEN type = 4 THEN v END) col4
FROM (
SELECT row_number() OVER(partition BY col1 ORDER BY CASE WHEN col2 IS NULL THEN 1 ELSE 0 END, @@spid) AS row2
, row_number() OVER(partition BY col1 ORDER BY CASE WHEN col3 IS NULL THEN 1 ELSE 0 END, @@spid) AS row3
, row_number() OVER(partition BY col1 ORDER BY CASE WHEN col4 IS NULL THEN 1 ELSE 0 END, @@spid) AS row4
, *
FROM
(
VALUES (1, NULL, N'a', NULL)
, (1, N'b', NULL, NULL)
, (1, NULL, NULL, N'c')
, (2, N'aa', NULL, NULL)
, (2, NULL, N'bb', NULL)
, (3, N'aa', NULL, 'cc')
, (3, 'xy', N'bb', NULL)
) t (col1,col2,col3,col4)
) x
CROSS APPLY (
VALUES (col2, row2, 2)
, (col3, row3, 3)
, (col4, row4, 4)
) up (v, row, type)
GROUP BY row, col1
HAVING count(v) > 0
- First, i create 3 row_numbers which sort each column into null and non null values. Here, you should substitute @@SPID with real column
- Then, I create an unpivot which generates a row for each column and type, this is so we can collapse the values
- Finally, a conditional aggregation collapses the values back per type, which generates col2,col3,col4.
- HAVING count(v) > 0 removes now completely empty rows from the equation.
Outputs:
| col1 |
col2 |
col3 |
col4 |
| 1 |
b |
a |
c |
| 2 |
aa |
bb |
NULL |
| 3 |
xy |
bb |
cc |
| 3 |
aa |
NULL |
NULL |