in
Eric Vaillancourt on SQL Server...

MS SQL Dev

Pivots with Dynamic Columns in SQL Server 2005/2008

Bookmark and Share

Pivots in SQL Server 2005/2008 can convert row into column data. Pivots are frequently used in reports, and are reasonably easy to work with.

 

However, many people have asked me how to make the column list dynamic.  Normally, this list is fixed, but many times the new columns are determined by the data at a later stage. This problem is easily solved when we mix pivots with dynamic SQL, so here is a very simple example about how to dynamically generate the pivot statement:

 

PIVOT allows you to turn data rows into columns. For example, if you have a query like this:

 

USE AdventureWorks

GO

SELECT * FROM

      (SELECT CustomerID, DATEPART(m, OrderDate) OrderMonth, SubTotal

                  FROM Sales.SalesOrderHeader

                  WHERE OrderDate between '20030101' and '20031231'

                  and CustomerID IN (2,4,6,7,8,9)) src

PIVOT (SUM(SubTotal) FOR OrderMonth

IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12])) AS pvt

GO

 

clip_image002

 

The rows coming from the internal query are transposed into colums:

 

SELECT * FROM

      (SELECT CustomerID, DATEPART(m, OrderDate) OrderMonth, SubTotal

                  FROM Sales.SalesOrderHeader

                  WHERE OrderDate between '20030101' and '20031231'

                  and CustomerID IN (2,4,6,7,8,9)) src

PIVOT (SUM(SubTotal) FOR OrderMonth

IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12])) AS pvt

 

This is ok if the colum list suppied in the IN clause is fixed like the 12 months of the year.  But if the list evolves with the data, you would have to re-write your pivot.  Not to practical.

 

Let’s look at another example:

 

SELECT * FROM

      (SELECT CustomerID, YEAR(OrderDate) OrderYear, SubTotal

            FROM Sales.SalesOrderHeader

            WHERE CustomerID >=1 and CustomerID <=35) src

PIVOT (SUM(SubTotal) FOR OrderYear

IN ([2002],[2003])) AS pvt

GO

 

In this pivot example, we want to display a colums for each year and a row for each customer:

 

clip_image004

 

Notice that we are only displaying data for years 2002 and 2003.  We could modify our pivot to make it dynamic.

 

Look at the following code:

 

DECLARE @listCol VARCHAR(2000)

SELECT  @listCol = STUFF(( SELECT DISTINCT

                                '],[' + ltrim(str(YEAR(OrderDate)))

                        FROM    Sales.SalesOrderHeader

                        ORDER BY '],[' + ltrim(str(YEAR(OrderDate)))

                        FOR XML PATH('')

                                    ), 1, 2, '') + ']'

 

By using the combination of STUFF and FOR XML PATH we can build a string that concatenates all columns by doing a SELECT DISTINCT on our table before doinf the pivot.

 

After executing this piece of code, you should get in the @listCol variable the list of colums needed to do the pivot.

 

clip_image006

 

Now, all we have to do is to convert our pivot into a dynamic query:

 

DECLARE @listCol VARCHAR(2000)

DECLARE @query VARCHAR(4000)

SELECT  @listCol = STUFF(( SELECT DISTINCT

                                '],[' + ltrim(str(YEAR(OrderDate)))

                        FROM    Sales.SalesOrderHeader

                        ORDER BY '],[' + ltrim(str(YEAR(OrderDate)))

                        FOR XML PATH('')

                                    ), 1, 2, '') + ']'

 

SET @query =

'SELECT * FROM

      (SELECT CustomerID, YEAR(OrderDate) OrderYear, SubTotal

            FROM Sales.SalesOrderHeader

            WHERE CustomerID >=1 and CustomerID <=35) src

PIVOT (SUM(SubTotal) FOR OrderYear

IN ('+@listCol+')) AS pvt'

 

EXECUTE (@query)

 

Et voila:

 

clip_image008

 

 

Hope this was helpful,

 

Eric Vaillancourt

www.sqlprof.com

 

Comments

 

DotNetKicks.com said:

You've been kicked (a good thing) - Trackback from DotNetKicks.com

April 12, 2008 10:43 AM
 

thorkyl said:

This is fantastic, well written.

April 30, 2008 4:42 PM
 

How to pivot data | keyongtech said:

Pingback from  How to pivot data | keyongtech

January 18, 2009 11:41 AM
 

?????????????????? » SQL?????????????????? 9?????? said:

Pingback from  ?????????????????? &raquo; SQL?????????????????? 9??????

May 29, 2010 2:49 PM
 

?????????????????? » SQL?????????????????? 10?????? said:

Pingback from  ?????????????????? &raquo; SQL?????????????????? 10??????

June 5, 2010 7:38 AM
 

Pivots take work | Tim's Dev Blog said:

Pingback from  Pivots take work | Tim&#039;s Dev Blog

October 7, 2010 10:38 PM
 

Dark Under Eye said:

Pingback from  Dark Under Eye

March 10, 2011 9:19 PM
 

Dark Under Eye said:

Pingback from  Dark Under Eye

March 10, 2011 9:19 PM
 

Access to SQL Sever- Pivots « Joshua Doodnauth's Blog said:

Pingback from  Access to SQL Sever- Pivots &laquo;  Joshua Doodnauth&#039;s Blog

April 6, 2011 12:39 PM
 

SQL | ???????????????? said:

Pingback from  SQL | ????????????????

July 27, 2011 4:13 AM
 

SQL?????????????????? 12?????? | wp-test????????? said:

Pingback from  SQL?????????????????? 12?????? | wp-test?????????

November 11, 2011 1:42 AM
 

SQL?????????????????? 12?????? | wp-test????????? said:

Pingback from  SQL?????????????????? 12?????? | wp-test?????????

November 11, 2011 2:01 AM
 

Newbie Questions - Insert From XML - dBforums said:

Pingback from  Newbie Questions - Insert From XML - dBforums

November 17, 2011 11:44 AM

About Eric Vaillancourt

Eric Vaillancourt possède plus de vingt ans d'expérience en programmation de base de données et en gestion de projets. Depuis une dizaine d’années, il se spécialise en optimisation des performances et en coaching d’administrateurs de bases de données. Il a occupé des postes de haute direction dans le secteur privé, principalement dans des firmes technologiques. Il a eu l'occasion de gérer plusieurs projets liés au développement des affaires et aux changements organisationnels.
©2008 SQLProf.com & Eric Vaillancourt
Powered by Community Server (Non-Commercial Edition), by Telligent Systems