UNPIVOT and CASE to solve a problem to find the highest column in a row

by Allan Svelmøe Hansen June 06, 2008 17:37

A problem which was posted on a forum was how to select the highest valued column from a row, given a specific set up.
The design of the table was like this:

Table layout for the Score table

And content looked something like this:
Sample content for Score table

Being personally interested in SQL I thought this was a fun little problem to test out myself, so I gave it a shot. Now the way I would have done this in the old day and the “easiest to think up” solution (in my opinion) was to simply case my way through it.
Making something like this:

SELECT PersonName,
    
CASE
    
WHEN  Score1 Score2 THEN
    
CASE
        
WHEN  Score2 Score3 THEN Score3 --Score3 is highest
        
ELSE Score2 --Score2 is highest
    
END
    ELSE
        
CASE
            
WHEN Score1 Score3 THEN Score3 --Score3 is highest
            
ELSE Score1 --Score1 is higest
        
END
END AS 
HighScore
FROM Score
 
GO


Simple enough and it returns:
Result of the CASE query


However, because I’m working with SQL Server 2005 and have started to explore the syntax possibilities of that one, and – well because the shown CASE syntax isn’t exactly user friendly to read, for people to maintain, or even worse, if a Score4 is suddenly introduced. The complexity in it can quickly become unsurmountable.
So I thought about it a bit and I recalled the PIVOT syntax that it could flip table rows into columns, and the UNPIVOT which could flip columns into rows. This makes UNPIVOT fit this problem exactly.
So I started to build a query using UNPIVOT:

SELECT PersonNameUnPivotColumnNameUnPivotScore
    
FROM
    
(
        
SELECT PersonNameScore1Score2Score3
        
FROM ScoreT1
    UNPIVOT
    
(
        
UnPivotScore FOR UnPivotColumnName IN (Score1Score2Score3)
    )
T2

GO 


Which gave me the result like this:
Result of the first step of UNPIVOT

Now that is halfway there, now I only needed to group on the Name and select the higest score. For this I decided to use the Common Table Expression syntax instead of making a tempoary table … simply because I like CTE’s :)
That resulted in this query:

WITH UnpivotCTE AS (
    
SELECT PersonNameUnPivotColumnNameUnPivotScore
    
FROM
    
(
        
SELECT PersonNameScore1Score2Score3
        
FROM ScoreT1
    UNPIVOT
    
(
        
UnPivotScore FOR UnPivotColumnName IN (Score1Score2Score3)
    )
T2
    
)
SELECT PersonNameMAX(UnPivotScoreAS HighScore
FROM UnpivotCTE
GROUP BY PersonName
GO
 

Which resulted in the same result as my “CASE” syntax.

I then quickly – just for fun – ran an estimated query plan for both, and the CASE was significantly faster, but I would argue that the manageability of the latter (UNPIVOT) is vastly improved, because as I mentioned ealier – imagine if we needed to add a column Score4 or perhaps a Score5, 6 and 7 as well. Imagine how the CASE would look then, whereas I could simply expand on the UNPIVOT syntax easily.

Bookmark and Share DotnetKicks dotnetshoutout

Comments

Add comment




  Country flag

biuquote
  • Comment
  • Preview
Loading



Powered by BlogEngine.NET 1.6.1.0
Theme by Mads Kristensen | Modified by Mooglegiant

About:
Allan Svelmøe Hansen

My real name is Allan Svelmøe Hansen.
I live in Denmark, where I work as a developer for hedal:kruse:brohus using SQL Server and the .NET framework since 2004.
My primary fields of expertise is back-end data integration, database design and optimization.


       View Allan Svelmøe Hansen's profile on LinkedIn     

Disclaimer

The opinions expressed herein are my own personal opinions and thoughts and does not represent my employers view in any way, nor are my results guaranteed for all situations.
Content is presented "as is", with no warranty.