How-To Develop CrossTab Queries in T-SQL(Transact-SQL) with Dynamic Columns

Dynamic Cross Tab Queries in T-SQL

© Kevin Languedoc 2010

Creating Cross Tab Style queries in SQL Server is always a challenge. Several design pattern have emerge over the years that I always found to be a bit lacking. This tutorial will demonstrate a simple but very powerful way to create Cross Tab queries with Dynamic Columns. By this I mean that you don’t know the column names beforehand.

My method involves using “For XML” which was also introduced with SQL Server 2000 to provide a means to do string concatenation. This was further expanded with SQL Server 2005 to include the PATH clause which we will use to generate our dynamic columns. The rest of this article will demonstrate where to use For XML Path along with Pivot which was introduced SQL Server 2005 to create a flexible cross tab solution with dynamic columns.

I am going to perform the following steps:

  1. Create variables
  2. Select the values for my dynamic columns as xml
  3. Convert the xml into a string
  4. Write the query
  5. Execute the query


Create the variables

We are going to need three variables for this example: One for the XML, one for the SQL query and one for the column string. @SQL is for the SQL query; @XML is for the XML that will be created with For XML Path and finally @Cols for the column string to be used in the Pivot procedure:


Declare @SQL VARCHAR(8000),
@XML XML,
@Cols VARCHAR(4000)


Next we are going to get our list of columns based on the values of a query that will return a list of values that can be used as columns names. In the following query we are selecting a list of products names from the ProductsCatalog table. The one caveat is that the values we are selecting here must also be in the table we will use for our cross tab query.

We will then enclose them in square brackets because the Pivot function in SQL server requires it as part of it syntax. This is a straightforward SELECT that I will assign to my @Cols variable. This query can as complex as you need it to be to return a single columns of values for the column headers in the Cross Tab result set.



Set @COL = (SELECT ', [' + Products + ']'
FROM ProductsCatalog
GROUP BY SKU
ORDER BY SKU
FOR XML PATH('')
)


The XML output would be like this:


<Products>,[Widget1] </Products>
<Products>,[Widget2] </Products>
<Products>,[Widget3] </Products>
<Products>,[Widget4] </Products>
<Products>,[Widget5] </Products>
<Products>,[Widget6] </Products>


However you would actually see the results in SSMS as a hyperlinked result as follows:

,[Widget1],[Widget2],[Widget3],[Widget4],[Widget5],[Widget6],[Widget7]

If you wanted to see the actual XML as above you would need to click on the results link. Next we need to convert this XML to a string which we will do as in the following section.

Convert the XML into a string

Converting the XML output to a string is quite straightforward. All you do is convert your XML to VARCHAR and specify that you only want DISTINCT values. You assign this string to a variable as you can see below.

SET @COLS = (SELECT DISTINCT CONVERT(VARCHAR(4000), @COLs) )

The second SET is to remove the leading comma“,” from the string.

SET @COLS = SUBSTRING(@COLS, 2, LEN(@COLS))

Now the only two steps left are to write the Query including the PIVOT clause and execute the query. First the query, here I am using a Select clause to retrieve the columns for my Pivot. The data is coming from the subquery and is used to sum the values in the val column using FOR [col3] clause. Notice the col3 column is enclosed in square brackets [] and is the same column that was used in the selection of the column names in the previous query. Finally, the columns names are enclosed in another set of parentheses and the PIVOT must be assigned an alias like “pt”. The same nomenclature applies to the data query; it must have an alias such as “data”. To finish off, the query is executed with a simple Exec(@Sql).

SET @SQL = 'Select * from
(
Select products, salesValues
from ProductSales
) data
PIVOT
(
Sum(salesValues) FOR [products] IN ('+@Cols +')
) pt'
Exec(@SQL)

This is a very simple example to explain the concepts in a, hopefully, clear way. This pattern lays out a simple and highly dynamic method of generating dynamic columns for your cross tab queries.

More by this Author


Comments 4 comments

Val 4 years ago

Kevin , You can simplify the preparation of the columns list. Check these articles where dynamic pivot is created using STUFF function:

http://r-tag.com/PivotSample.aspx

http://www.simple-talk.com/community/blogs/andras/...


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

Yes but your column names are hard coded. In the above example they are dynamic. For example if you were to display monthly sales only for months were there are sales.

The first example is similar to mine (r-tag), but I believe mine is simpler to implement and I use hundreds of times in various implementations.

K


Val 4 years ago

Kevin , columns are not hardcoded. In both examples the data retrieval is in 3 commands.


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

Sorry Val. So I guess there are different ways to implement this design.

    Sign in or sign up and post using a HubPages Network account.

    0 of 8192 characters used
    Post Comment

    No HTML is allowed in comments, but URLs will be hyperlinked. Comments are not for promoting your articles or other sites.


    Click to Rate This Article
    working