Switching rows and columns in SQL

Comments 0

Share to social media

Recently, I came across a description of a transformation operation using SQL Server CLR – the goal is to convert, or transpose, columns into rows and rows into columns. Microsoft ACCESS has a SQL TRANSFORM /PIVOT extension to SQL that automatically produces a crosstab query, and SQL Server 2005 introduced the pivot command, but neither simply swaps columns and rows. The problem was to replicate this sort of functionality in SQL Server. It’s possible to write a CLR function to transform the data, however, I believe that a set-based T-SQL query is the preferred solution to this type of problem.

In the example of the CLR transform function, the source data included columns for PaymentDate, and three types of payments:

917-image001.png

Once transformed the result would swap the columns and rows to this configuration:

917-image003.png

The following script creates the test table and populates it with the sample test data:

The root cause behind this transformation is that the three payment columns violate first normal form. Column names that include data (Medicare, Medicaid, VA) is clear indication that first normal form is being ignored with repeating columns. Had the source data been properly normalized there would been no need to transform the columns and rows. If you find yourself needing to perform this type of transformation regularly, then you have a problem with your schema design. A normalized version of the source table should have columns for PaymentDate, PaymentType, and Amount.

But assuming the denormalized data is all that’s available, Microsoft provides a straight-forward solution using the Pivot and UnPivot commands available since SQL Server 2005. The key is recognizing that the source data violated first normal form, and that the unpivot command is designed specifically to normalize this type of unnormalized data. In the query below, the sq subquery first uses an unpivot command to normalize the data which is then passed to the pivot command in the outer query. Pairing the unpivot and pivot command makes quick work of the transformation task. The only trick in the query is appending a “d” before each date so the pivot command will accept it as a column name:

We make some assumptions about the nature of the data when we use the MIN aggregate function. The routine expects to ignore duplicate entries for a particular PaymentDate if there are any.

Before SQL Server 2005, you would have had to use the slightly more convoluted code …

You’ll see that this would give different results from the first solution if there is duplicate data in the original aggregate table 

There have been several attempts to create a generic solution that emulates the TRANSFORM/PIVOT functionality ,(Rob Volk’s being probably the best known, Dynamic Cross-Tabs/Pivot Tables, but see also Creating cross tab queries and pivot tables in SQL) but the PIVOT/UNPIVOT functionality of SQL Server 2005 onwards makes such devices unnecessary.

The example provides two lessons for SQL server designers and developers. First – don’t underestimate the power of the set-based query. Turning to the CLR for a solution when T-SQL can solve the problem is nearly always an error. Perhaps a more significant lesion is that there’s a performance cost to denormalization when additional code is required to re-normalize the data. The programmer’s cliché, “Normalize till is hurts, then denormalize till it works,” simply isn’t true.

Article tags

Load comments

About the author

Paul Nielsen

See Profile

Paul Nielsen is a hands-on database developer, Microsoft SQL Server MVP, and trainer specializing in data architecture and database development using Microsoft SQL Server technologies. Active in the SQL Server community, Paul is the and founder of Colorado PASSCamp. Paul presents around the world at conferences such as Microsoft Tech Ed (Dev), SSWUG Virtual Conference, SQL Teach (Canada), SQL Open World (Denmark), and devLINK (Nashville), and PASS Summit. Besides holding several certifications, Paul is an instructor with Learning Tree, served on the Microsoft Education Domain Objectives panel for SQL Server 2005, and was the Design-SME (subject matter expert) for the Microsoft Official Course, 2784: Tuning and Optimizing Queries using Microsoft SQL Server 2005. Paul has been developing data-centric solutions since 1982, and was the Enterprise Data Architect for Compassion International, a SQL Server instructor with Learning Tree, the technical editor for a database magazine, and a U. S. Navy Submariner (Data Systems Tech Petty Officer).

Paul Nielsen's contributions
Paul Nielsen's latest contributions: