Archive for July 27th, 2009
From Stack Overflow:
I have a table and want to transpose its rows to columns, similar to a pivot table but without summarising.
For example I have the following tables:Question (QuestionID, QuestionText) Response (ResponseID, ResponseText, QuestionID)
Basically I want to be able to create a dynamic table something like:
Question 1 Question 2 Question 3 Response 1.1 Response 1.2 Response 1.3 Response 2.1 Response 2.2 Response 2.3 Response 3.1 Response 3.2 Response 3.3 Response 4.1 Response 4.2 Response 4.3
The main requirement would be I don’t know at design time what the question text will be.
First, let’s put it straight: SQL is not a right tool to do this.
SQL operates on sets. An SQL query is a functions that returns a set. And the column layout is an implicit property of a set. It should be defined in design time. This is the way SQL works.
However, there are several approaches that can simplify the task. One of them is using SQL Server‘s XML abilities.
To arrange the answers in a table, we need to make the following:
- Select all questions. This rowset will define the columns of our table.
- Select the row numbers for all answers for the question that has the most answers. This rowset will define the rows of our table. The number of rows wil be exactly as the number of answers to the most answered question.
- Assign the ordinal number to each answer on any question. This is done using
ROW_NUMBER(). This value will uniquely define the position of the answer in a table.
- For each row (taken from the rowset made on step 2), take all the questions and
LEFT JOINthe answers that need to be put into this row, using the ordinal number calculated on the step 3 as a
LEFT JOINcondition. This will put either the answer or an empty string into the corresponding cell.
- Transform the rowset retrieved on step above into an XML string made out of
<td>‘s and enclosed into a
- Transform the resulting rowset into an XML made out of the XML‘s from the previous step and enclosed into a
Let’s create a sample table and see how can we do this: