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:
- Create variables
- Select the values for my dynamic columns as xml
- Convert the xml into a string
- Write the query
- 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),
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 + ']'
GROUP BY SKU
ORDER BY SKU
FOR XML PATH('')
The XML output would be like this:
However you would actually see the results in SSMS as a hyperlinked result as follows:
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
Sum(salesValues) FOR [products] IN ('+@Cols +')
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.