For this challenge #10, Rob comes with a very nice solution, he was also part of the winners in the TSQL Challenge #9 in July.

Owner/Principal of LobsterPot Solutions, is a SQL MVP and MCT based in Adelaide, Australia where he runs the local SQL Server User Group. He consults and trains across Australia, helping people improve the way they use their databases. He has also helped create exams for Microsoft Learning and is a regular presenter at conferences around Australia. His company can be found at http://www.lobsterpot.com.au and his blog at http://msmvps.com/blogs/robfarley
The Rob's solution is based on PIVOT and UNPIVOT operators These feature is available since SQL Server 2005 and enable to change a table-valued expression into another table. It's perfect to order horizontally and vertically data.
How did Rob work on this challenge?
Here is the approach taken by Rob on this challenge as he explains us:
The problem here focuses on having to sort data across columns, not just in by rows. Thing is - SQL Server doesn't allow for sorting across columns very well. This is where the problem becomes an interesting one. I figured that since I can easily order rows, why not unpivot the data, so that I could then order it and pivot it back into the required shape.
Using ROW_NUMBER(), I can make sure that I can order the values that had been in columns, using the PARTITION BY clause to make sure that I'm keeping track of which row the values had originally come from.
I use CTEs throughout the problem, as I find them generally more effective than temporary tables or table variables.
Here is the final solution provided by Rob with the comments inline:
--Let's start by unpivotting the data we have.
WITH
unpivotted AS (
SELECT *
FROM (
/*Rownum makes sure we don't lose track of which row is which in
our original data.I'm not actually interested in which order
ROW_NUMBER() gets applied, I just want to make sure that each
row is uniquely identified. Therefore, ORDER BY (SELECT 1) is
used - just arbitrarily assigning row numbers.*/
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rownum, *
FROM @t
) t UNPIVOT (vals FOR col IN (c1,c2,c3)) p
)
,
/*Now we can provide an order for the columns,
to do the horizontal order*/
ordered_cols AS (
SELECT rownum, vals,
ROW_NUMBER() OVER (
PARTITION BY rownum ORDER BY vals) AS colnum
FROM unpivotted
)
/*Finally we can pivot them back again, and use
DISTINCT to de-dup the data*/
SELECT DISTINCT [1] AS [C1], [2] AS [C2], [3] as [C3]
FROM ordered_cols
PIVOT
(MAX(vals) FOR colnum IN ([1],[2],[3])) p
ORDER BY [1], [2], [3]
;
What can we learn from this?
We have here a nice example of the use of PIVOT/UNPIVOT functions and how to combine them to make a complex operation.
The key point here was to consider the initial table as an aggregated data table already pivoted. The idea is simple, if you want to make some ordering in your columns (obviously if they carry the same kind of data), put them in rows! That’s why the first step is to unpivot the original table.
Just try this simple sample to compare:
--ORIGINAL
SELECT c1='2',c2='1',c3='3' UNION
SELECT '3','2','1' UNION
SELECT 'Z','X','Y'
--UNPIVOTED
;WITH
REPIVOT AS (
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rownum, *
FROM (
SELECT c1='2',c2='1',c3='3' UNION
SELECT '3','2','1' UNION
SELECT 'Z','X','Y'
) ORIGINAL UNPIVOT (vals FOR col IN (c1,c2,c3)) p
)
SELECT * FROM REPIVOT
Which will give us:
Then you are able to make your specific computation over rows and columns (an ordering in our case) and then make a normal pivot to put again the data in the right way.
These functions where introduced in Sql Server 2005 and even if they are not well used by everyone they are really useful. And as usual with integrated functions the code is easier to read and the performances better than an home mode script to make this pivot/unpivot.
A final word
So, congratulations again Rob for this challenge and thank you for this explanation! We hope to see you soon in a next challenge.
We will continue in the next days with the solutions from Divya and Alejandro and don’t miss the next challenge by the end of the week!
About the Authors.