Transpose Row to Column in SQL Server 2000 - sql

I am trying to convert rows into columns in SQL Server 2000. Although all rows converted into required columns but i unable to get the value converted into the respective columns.
My code is:
DROP TABLE prePivot1
DROP TABLE results1
CREATE TABLE prePivot1 (
[StudentId] uniqueidentifier
, [Sub_Abbr] Varchar(100)
, [Total_marks] MONEY
)
CREATE TABLE results1 (
[StudentId] uniqueidentifier
)
INSERT INTO prePivot1
SELECT '{4FD7CBBA-1621-4102-B4A3-000BF92E2F6E}', 'ENG', 55
UNION SELECT '{4FD7CBBA-1621-4102-B4A3-000BF92E2F6E}', 'MBEN', 90
UNION SELECT '{4FD7CBBA-1621-4102-B4A3-000BF92E2F6E}', 'ECO', 80
UNION SELECT '{4FD7CBBA-1621-4102-B4A3-000BF92E2F6E}', 'PSc', 45
UNION SELECT '{4FD7CBBA-1621-4102-B4A3-000BF92E2F6E}', 'PSY', 23
UNION SELECT '{AD288712-5C97-446B-8AFE-003FC845B56B}', 'ENG', 90
UNION SELECT '{AD288712-5C97-446B-8AFE-003FC845B56B}', 'ECO', 44
UNION SELECT '{AD288712-5C97-446B-8AFE-003FC845B56B}', 'PSc', 45
UNION SELECT '{AD288712-5C97-446B-8AFE-003FC845B56B}', 'BST', 23
UNION SELECT '{AD288712-5C97-446B-8AFE-003FC845B56B}', 'ASS', 80
UNION SELECT '{AD288712-5C97-446B-8AFE-003FC845B56B}', 'PSY', 93
DECLARE #sql VARCHAR(8000)
DECLARE #pivot varchar(10)
DECLARE pivotCursor CURSOR LOCAL READ_ONLY FOR
SELECT DISTINCT
[Sub_abbr]
FROM
prePivot1
OPEN pivotCursor
FETCH NEXT FROM pivotCursor INTO #pivot
WHILE (##FETCH_STATUS = 0) BEGIN
SET #sql = '
ALTER TABLE results1 ADD [' + CAST(#pivot AS VARCHAR(10)) + '] INT'
EXEC (#sql)
FETCH NEXT FROM pivotCursor INTO #pivot
END
CLOSE pivotCursor
INSERT INTO results1 ([studentId])
SELECT DISTINCT [StudentId] FROM prePivot1
OPEN pivotCursor
FETCH NEXT FROM pivotCursor INTO #pivot
WHILE (##FETCH_STATUS = 0) BEGIN
SET #sql = '
UPDATE results1
SET
[' + CAST(#pivot AS VARCHAR(10)) + '] = pp.[total_marks]
FROM
prePivot1 pp
WHERE
pp.[total_marks] = ' + CAST(#pivot AS VARCHAR(10)) + '
AND pp.[studentId] = results1.[studentId]'
EXEC (#sql)
FETCH NEXT FROM pivotCursor INTO #pivot
END
CLOSE pivotCursor
DEALLOCATE pivotCursor
SELECT * FROM results1
Please help me how do i do to get the expected result.
Thanking you in advance.

There are a couple of things wrong with your predicate here:
pp.[total_marks] = ' + CAST(#pivot AS VARCHAR(10)) + '
You are filtering on the wrong column
You are not generating a proper string with the #pivot part.
This is what it looks like when you print out your dynamic sql string. Notice that it causes a join on prePivot1.total_marks column to results1.ECO column which is not what you're intending.
UPDATE
results1
SET
[ECO] = pp.[total_marks]
FROM
prePivot1 AS pp
WHERE
pp.[total_marks] = ECO
AND pp.[studentId] = results1.[studentId]
Corrected version (you also don't need to cast the variable):
pp.[Sub_Abbr] = ''' + #pivot + '''
A slightly less error prone solution would be to parameterize your dynamic sql:
-- Change #sql --> nvarchar(4000)
SET #sql = N'
UPDATE
results1
SET
' + QUOTENAME(#pivot) + N' = pp.[total_marks]
FROM
prePivot1 AS pp
WHERE
pp.[Sub_Abbr] = #Sub_Abbr
AND pp.[studentId] = results1.[studentId];';
EXEC sp_executesql
#stmt = #sql,
#params = N'#Sub_Abbr varchar(10)',
#Sub_Abbr = #pivot;
This is the general pattern I've used in sql2k to pivot just for reference:
(I'm assuming here that StudentId, Sub_Abbr is unique though the schema doesn't explicitly confirm this)
SELECT
[StudentId],
MAX(CASE WHEN [Sub_Abbr] = 'ASS' THEN [Total_marks] ELSE NULL END) AS [ASS],
MAX(CASE WHEN [Sub_Abbr] = 'BST' THEN [Total_marks] ELSE NULL END) AS [BST],
MAX(CASE WHEN [Sub_Abbr] = 'ECO' THEN [Total_marks] ELSE NULL END) AS [ECO],
MAX(CASE WHEN [Sub_Abbr] = 'ENG' THEN [Total_marks] ELSE NULL END) AS [ENG],
MAX(CASE WHEN [Sub_Abbr] = 'MBEN' THEN [Total_marks] ELSE NULL END) AS [MBEN],
MAX(CASE WHEN [Sub_Abbr] = 'PSc' THEN [Total_marks] ELSE NULL END) AS [PSc],
MAX(CASE WHEN [Sub_Abbr] = 'PSY' THEN [Total_marks] ELSE NULL END) AS [PSY]
FROM
[dbo].[prePivot1]
GROUP BY
[StudentId];

Related

Dynamic Database in SubQuery

SELECT
email, password,GP_employee_id, company,
(select distinct CHEKNMBR from [BSL].[dbo].[UPR30300] WHERE EMPLOYID = GP_employee_id and CHEKDATE > GETDATE() - 20 ) as slip_number,
(select distinct CONVERT(date , CHEKDATE) from [BSL].[dbo].[UPR30300] WHERE EMPLOYID = GP_employee_id and CHEKDATE > GETDATE() - 20 ) as slip_number
FROM [payslips].[dbo].[myapp_user]
I would like [BSL] to be dynamic. The value would depend on the company field of the main query. So I want something like this [company].[dbo].[UPR30300]
You can do one big dynamic UNION ALL query
DECLARE #unioned nvarchar(max) = (
SELECT STRING_AGG(CAST(
'
SELECT *, company = ' + QUOTENAME(company, '''') + '
FROM ' + QUOTENAME(company) + '.[dbo].[UPR30300]
WHERE CHEKDATE > DATEADD(day, -20, GETDATE())
'
AS nvarchar(max)), 'UNION ALL')
FROM (
SELECT DISTINCT company
FROM [payslips].[dbo].[myapp_user]
) au
);
DECLARE #sql nvarchar(max) = '
SELECT
au.email,
au.password,
au.GP_employee_id,
au.company,
slip_number = u.CHEKNMBR,
slip_number2 = CONVERT(date, u.CHEKDATE)
FROM [payslips].[dbo].[myapp_user] au
LEFT JOIN (
' + #unioned + '
) u ON u.company = au.company
AND u.EMPLOYID = au.GP_employee_id;
';
PRINT #sql; -- for testing
EXEC sp_executesql #sql;
DECLARE #sql VARCHAR(1000);
DECLARE #company VARCHAR(50);
DROP TABLE IF EXISTS #myapp_user;
CREATE TABLE #myapp_user
(
email VARCHAR(256),
[password] VARCHAR(256),
GP_employee_id INT,
slip_number INT,
slip_number2 INT
);
DECLARE db_cursor CURSOR FOR
SELECT DISTINCT company FROM [payslips].[dbo].[myapp_user];
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #company
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql = '
SELECT
email,
password,
GP_employee_id,
slip_number = (select distinct CHEKNMBR from ' + QUOTENAME(#company) + '.[dbo].[UPR30300] WHERE EMPLOYID = GP_employee_id and CHEKDATE > GETDATE() - 20),
slip_number2 = (select distinct CONVERT(date , CHEKDATE) from ' + QUOTENAME(#company) + '.[dbo].[UPR30300] WHERE EMPLOYID = GP_employee_id and CHEKDATE > GETDATE() - 20)
FROM
[payslips].[dbo].[myapp_user]';
INSERT INTO #myapp_user EXECUTE (#sql);
FETCH NEXT FROM db_cursor INTO #company;
END
CLOSE db_cursor
DEALLOCATE db_cursor
SELECT * FROM #myapp_user;

Is there a better way to find a specific value in dynamic query?

I'm trying to find out is there a value in a dynamic query, at the moment I'm using this solution:
DECLARE
#SQL NVARCHAR(MAX)
, #ISLN NUMERIC(9,0) = '967272'
SET #SQL =
'SELECT *
FROM ITEM
LEFT OUTER JOIN SHIPMENT_DETAIL
ON ITEM.ITEM = SHIPMENT_DETAIL.ITEM
AND (SHIPMENT_DETAIL.COMPANY = ITEM.COMPANY OR ITEM.COMPANY IS NULL)
WHERE (SHIPMENT_DETAIL.warehouse = N''SH'' )
ORDER BY ITEM.ITEM ASC'
SELECT #SQL = STUFF (
#SQL
, 8
, 1
, 'INTERNAL_SHIPMENT_LINE_NUM'
)
DECLARE #TEMP TABLE (ISLN NUMERIC(9,0))
INSERT INTO #TEMP (ISLN)
EXEC SP_SQLEXEC #SQL
IF EXISTS (SELECT 1 FROM #TEMP WHERE ISLN = #ISLN)
SELECT 1
ELSE
SELECT 0
Dynamic SQL is generated by other software, so I cannot change the input data.
Is there a better way to find specific value in specific column of a dynamic query?
Try this, hope it will help you:
DECLARE
#SQL NVARCHAR(MAX)
, #ISLN NUMERIC(9,0) = '967272'
SET #SQL =
'SELECT *
FROM ITEM
LEFT OUTER JOIN SHIPMENT_DETAIL
ON ITEM.ITEM = SHIPMENT_DETAIL.ITEM
AND (SHIPMENT_DETAIL.COMPANY = ITEM.COMPANY OR ITEM.COMPANY IS NULL)
WHERE (SHIPMENT_DETAIL.warehouse = N''SH'' )
ORDER BY ITEM.ITEM ASC'
SELECT #SQL = 'if exists (' + STUFF (
#SQL
, charindex('where', #sql) + 6
, 0
, 'INTERNAL_SHIPMENT_LINE_NUM = ' + cast(#isln as varchar(20)) + ' and '
) + ') select 1 else select 0;';
EXEC SP_SQLEXEC #SQL;

How to loop through several database in SQL server 2005?

I have around 50 different databases and inside each of these database there is a table with the same name. Now, I have a written a query which extract selected fields from the table, but I need to manually select the database. How do I write a query so that I can pass database name and pull the data from that table?
Here is my code:
;WITH Review as (
select external_id as sponsorid, name as sponsorname, memberid, startdate, paidamt, code
from test.dev.sraw c left join client.dbo.sponsors s on c.customerid = s.external_id
where year(startdate) >2009 and startdate <> '0001-01-01' and startdate <> '1000-01-01'),
FinalDataCollection as (select sponsorid, sponsorname, count(*) as NbrOfClaims, count(distinct memberid) as NbrOfMembers, month(startdate) as mnth, year(startdate) as yr, sum(cast(paidamt as money)) as dollars, case when code > '0' then 'RX' else 'med' end as category, case when count(distinct memberid)> 0 then sum(cast(paidamt as money))/count(distinct memberid) else 0 end as costpm
from Review
group by sponsorid, sponsorname,year(startdate), month(startdate),case when code > '0' then 'RX' else 'med' end)
select * from FinalDataCollection
UPDATE #1
How do I replace ''SELECT top 5 * FROM '' + #db + ''.dbo.RAW'' of the following query with the above SQL query that start with ;WITH CTE
DECLARE #dbname NVARCHAR(200)
DECLARE #SQLString NVARCHAR (MAX)
SET #SQLString =
'DECLARE #db NVARCHAR(255)
DECLARE DB_CURSOR CURSOR LOCAL FAST_FORWARD FOR
SELECT db.name from sys.databases db WHERE db.name IN
(''A'',''B'',''C'' ) ORDER BY db.name
OPEN DB_CURSOR
FETCH NEXT FROM DB_CURSOR INTO #db
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC(''SELECT top 5 * FROM '' + #db + ''.dbo.RAW'')
FETCH NEXT FROM DB_CURSOR INTO #db
END
CLOSE DB_CURSOR
DEALLOCATE DB_CURSOR'
EXEC sp_executesql #SQLString
Thank you
You could create a stored procedure having one parameter #DbName thus:
CREATE PROCEDURE dbo.GetDataFromMyTable (
#DbName SYSNAME -- or NVARCHAR(128)
)
AS
BEGIN
IF DB_ID(#DbName) IS NOT NULL AND #DbName IN (N'MyDB1', N'MyDB2', N'MyDB3', ...)
BEGIN
DECLARE #SqlStatement NVARCHAR(MAX);
SET #SqlStatement = N'USE ' + QUOTENAME(#DbName) + N'; SELECT t.Col1, t.Col2 FROM dbo.MyTable';
EXEC sp_executesql #SqlStatement;
END
ELSE
RAISERROR('Wrong database.', 16, 1);
END
END;
Notes:
DB_ID(#DbName) IS NOT NULL -- It checks if #DbName exists
#DbName IN (N'MyDB1', N'MyDB2', ..., N'MyDBn') -- It checks if #DbName is on the white list with allowed database (from this point of view, first check is, somehow, redundant).
Why I've used QUOTENAME(#DbName) ? See section Wrapping Parameters with QUOTENAME() and REPLACE(): if the content of #variable is a securable (ex. a database / table) then the recommended wrapper is QUOTENAME(#variable).
You could replace #DbName IN (N'MyDB1', N'MyDB2', ..., N'MyDBn') with exists thus:
EXISTS (
SELECT *
FROM (
SELECT N'MyDB1' UNION ALL
SELECT N'MyDB2' UNION ALL
...
SELECT N'MyDBn'
) dbs(DbName)
WHERE dbs.DbName = #DbName
)
Update #1:
You have to replace
SELECT t.Col1, t.Col2 FROM dbo.MyTable
with
WITH Review as (
select external_id as sponsorid, name as sponsorname, memberid, startdate, paidamt, code
from test.dev.sraw c left join client.dbo.sponsors s on c.customerid = s.external_id
where year(startdate) >2009 and startdate <> ''0001-01-01'' and startdate <> ''1000-01-01''),
FinalDataCollection as (select sponsorid, sponsorname, count(*) as NbrOfClaims, count(distinct memberid) as NbrOfMembers, month(startdate) as mnth, year(startdate) as yr, sum(cast(paidamt as money)) as dollars, case when code > ''0'' then ''RX'' else ''med'' end as category, case when count(distinct memberid)> 0 then sum(cast(paidamt as money))/count(distinct memberid) else 0 end as costpm
from Review
group by sponsorid, sponsorname,year(startdate), month(startdate),case when code > ''0'' then ''RX'' else ''med'' end)
select * from FinalDataCollection

SQL Stored procedure, Output rows as columns for summary

Using SQL 2005
Here is what my SQL results look like
UserID | Frame | Choice | Description | DateTime
------------------------------------------------
bcn005 | PL_P03| 1 | Rules-Based | 2011-10-24 14:14:26
bcn005 | PL_P04| 0 | VirtueBased | 2011-10-24 14:16:37
...
bmk172 | Prac_1| 0 | None | 2011-10-25 12:45:38
...
My client wants the results to look like this
UserID | Frame | Choice | Description | DateTime | Frame | Choice | Description | DateTime
-------------------------------------------------------------------------------------------
bcn005 | PL_P03| 1 | Rules-Based | 2011-10-..| PL_P04| 0 | VirtueBased | 2011-10-..
bmk172 | Prac_1| 0 | None | 2011-10-..|
Where all of a participants responses are on one row. There basically needs to be another set of Frame/Choice Description/DateTime for every row of the result set.
These are survey results, but it is the type of survey where one participant might have went back and changed their answer 5 times. So the amount of Frame/Choice Description/DateTime for each UserID will be different.
I know I should use a stored procedure (or maybe even an excel macro) but I am completely new to both of these. Any guidance is appreciated. Here is my SQL query
select UserID, locationName AS 'Frame', student_response AS 'Choice',
description, DateTime
from tblStudentResponses
WHERE GroupID in (18,20,21,36,37,38,39,40)
AND UserID in (SELECT UserID FROM tblStudentResponses WHERE
locationName = 'Character1Certificate')
AND DateTime > '2011-10-01'
AND type = 'choice'
order by UserID
!! UPDATE !! Full working solution and test code
--Sample Data Preperation
DECLARE #FrameChoices as TABLE(UserId varchar(50),Frame varchar(50),Choice varchar(4000),Description varchar(1000),[DateTime] DateTime)
--Test Values
INSERT INTO #FrameChoices(UserId,Frame,Choice,Description,[DateTime])
SELECT UserId,Frame,Choice,Description,[DateTime]
FROM (
SELECT 'bcn005' AS UserId, 'PL_P03' AS Frame, '1' AS Choice, 'Rules-Based'
AS Description, '2011-10-24 14:14:26' AS [DateTime]
UNION ALL
SELECT 'bcn005' AS UserId, 'PL_P04' AS Frame, '0' AS Choice, 'VirtueBased'
AS Description, '2011-10-24 14:16:37' AS [DateTime]
UNION ALL
SELECT 'bmk172' AS UserId, 'Prac_1' AS Frame, '0' AS Choice, 'None' AS
Description, '2011-10-25 12:45:38' AS [DateTime]
) T
-- Dynamic SQL Preparation
DECLARE #SQL VARCHAR(MAX)
DECLARE #MaxNumberOfFrames INT
SET #SQL = ''
SET #MaxNumberOfFrames = 1
SELECT #MaxNumberOfFrames = MAX(FrameCount)
FROM
(
SELECT COUNT(1) FrameCount
FROM #FrameChoices
GROUP BY UserId
) T
--needed to be part of the SQL string to EXEC at the bottom
SET #SQL = 'DECLARE #FrameChoices as TABLE(UserId varchar(50),Frame varchar(50),Choice varchar(4000),Description varchar(1000),[DateTime] DateTime)'
SET #SQL = #SQL + ' INSERT INTO #FrameChoices(UserId,Frame,Choice,Description,[DateTime])'
SET #SQL = #SQL + ' SELECT UserId,Frame,Choice,Description,[DateTime]'
SET #SQL = #SQL + ' FROM ('
SET #SQL = #SQL + ' SELECT ''bcn005'' AS UserId, ''PL_P03'' AS Frame, ''1'' AS Choice, ''Rules-Based'''
SET #SQL = #SQL + ' AS Description, ''2011-10-24 14:14:26'' AS [DateTime]'
SET #SQL = #SQL + ' UNION ALL'
SET #SQL = #SQL + ' SELECT ''bcn005'' AS UserId, ''PL_P04'' AS Frame, ''0'' AS Choice, ''VirtueBased'''
SET #SQL = #SQL + ' AS Description, ''2011-10-24 14:16:37'' AS [DateTime]'
SET #SQL = #SQL + ' UNION ALL'
SET #SQL = #SQL + ' SELECT ''bmk172'' AS UserId, ''Prac_1'' AS Frame, ''0'' AS Choice, ''None'' AS'
SET #SQL = #SQL + ' Description, ''2011-10-25 12:45:38'' AS [DateTime]'
SET #SQL = #SQL + ' ) T'
SET #SQL = #SQL + ' SELECT UserId'
--changed size to max
DECLARE #ColumnSQL VARCHAR(MAX)
DECLARE #CurrentFrame INT
SET #CurrentFrame = 1
WHILE (#CurrentFrame <= #MaxNumberOfFrames)
BEGIN
SET #ColumnSQL = ', MAX(CASE WHEN RowNumber ='+CAST(#CurrentFrame AS VARCHAR)+ ' THEN Frame ELSE '''' END) AS Frame_'+CAST(#CurrentFrame AS VARCHAR)
+ ', MAX(CASE WHEN RowNumber ='+CAST(#CurrentFrame AS VARCHAR)+ ' THEN Choice ELSE '''' END) AS Choice_'+CAST(#CurrentFrame AS VARCHAR)
+ ', MAX(CASE WHEN RowNumber ='+CAST(#CurrentFrame AS VARCHAR)+ ' THEN Description ELSE '''' END) AS Description_'+CAST(#CurrentFrame AS VARCHAR)
+ ', MAX(CASE WHEN RowNumber ='+CAST(#CurrentFrame AS VARCHAR)+ ' THEN [DateTime] ELSE NULL END) AS DateTime_'+CAST(#CurrentFrame AS VARCHAR)
SET #SQL = #SQL + #ColumnSQL
SET #CurrentFrame = #CurrentFrame + 1
END
SET #SQL = #SQL + ' FROM ( SELECT UserId,Frame,Choice,Description,[DateTime], ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY [DateTime]) AS RowNumber FROM #FrameChoices) T GROUP BY T.UserId'
PRINT #SQL
-- This generated SQL then can be executed by
EXEC(#SQL)
-- OR
EXEC SP_EXECUTESQL(#SQL)
-- Sample SQL generated from above query
DECLARE #FrameChoices as TABLE(UserId varchar(50),Frame varchar(50),Choice varchar(4000),Description varchar(1000),[DateTime] DateTime) INSERT INTO #FrameChoices(UserId,Frame,Choice,Description,[DateTime]) SELECT UserId,Frame,Choice,Description,[DateTime] FROM ( SELECT 'bcn005' AS UserId, 'PL_P03' AS Frame, '1' AS Choice, 'Rules-Based' AS Description, '2011-10-24 14:14:26' AS [DateTime] UNION ALL SELECT 'bcn005' AS UserId, 'PL_P04' AS Frame, '0' AS Choice, 'VirtueBased' AS Description, '2011-10-24 14:16:37' AS [DateTime] UNION ALL SELECT 'bmk172' AS UserId, 'Prac_1' AS Frame, '0' AS Choice, 'None' AS Description, '2011-10-25 12:45:38' AS [DateTime] ) T SELECT UserId, MAX(CASE WHEN RowNumber =1 THEN Frame ELSE '' END) AS Frame_1, MAX(CASE WHEN RowNumber =1 THEN Choice ELSE '' END) AS Choice_1, MAX(CASE WHEN RowNumber =1 THEN Description ELSE '' END) AS Description_1, MAX(CASE WHEN RowNumber =1 THEN [DateTime] ELSE NULL END) AS DateTime_1, MAX(CASE WHEN RowNumber =2 THEN Frame ELSE '' END) AS Frame_2, MAX(CASE WHEN RowNumber =2 THEN Choice ELSE '' END) AS Choice_2, MAX(CASE WHEN RowNumber =2 THEN Description ELSE '' END) AS Description_2, MAX(CASE WHEN RowNumber =2 THEN [DateTime] ELSE NULL END) AS DateTime_2 FROM ( SELECT UserId,Frame,Choice,Description,[DateTime], ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY [DateTime]) AS RowNumber FROM #FrameChoices) T GROUP BY T.UserId
If SQL 2005 or ABove you can try pivot.
If SQL 2000, then use combination of Group By and Case.
SELECT GC1,
GC2,
MAX(CASE WHEN CONDITION1 THEN Value1 ELSE Value2 END) AS DerivedColumn
FROM Table1
GROUP BY GC1, GC2
References:
SQL Server PIVOT and UNPIVOT
Pivot with Dynamic Column
Stack Overflow Pivot Question
[Solution]
-- Sample Data Preparation
DECLARE #FrameChoices TABLE
(
UserId varchar(20),
Frame varchar(20),
Choice int,
Description varchar(20),
[DateTime] DateTime
)
INSERT INTO #FrameChoices(UserId,Frame,Choice,Description,[DateTime])
SELECT UserId,Frame,Choice,Description,[DateTime]
FROM (
SELECT 'bcn005' AS UserId, 'PL_P03' AS Frame, 1 AS Choice, 'Rules-Based' AS Description, '2011-10-24 14:14:26' AS [DateTime]
UNION ALL
SELECT 'bcn005' AS UserId, 'PL_P04' AS Frame, 0 AS Choice, 'VirtueBased' AS Description, '2011-10-24 14:16:37' AS [DateTime]
UNION ALL
SELECT 'bmk172' AS UserId, 'Prac_1' AS Frame, 0 AS Choice, 'None' AS Description, '2011-10-25 12:45:38' AS [DateTime]
) T
-- Dynamic SQL Preparation
DECLARE #SQL VARCHAR(4000)
DECLARE #MaxNumberOfFrames INT
SET #SQL = ''
SET #MaxNumberOfFrames = 1
SELECT #MaxNumberOfFrames = MAX(FrameCount)
FROM
(
SELECT COUNT(1)FrameCount
FROM #FrameChoices
GROUP BY UserId
) T
SET #SQL = 'SELECT UserId'
DECLARE #ColumnSQL VARCHAR(512)
DECLARE #CurrentFrame INT
SET #CurrentFrame = 1
WHILE (#CurrentFrame <= #MaxNumberOfFrames)
BEGIN
SET #ColumnSQL = ', MAX(CASE WHEN RowNumber ='+CAST(#CurrentFrame AS VARCHAR)+ ' THEN Frame ELSE NULL END) AS Frame_'+CAST(#CurrentFrame AS VARCHAR)
+ ', MAX(CASE WHEN RowNumber ='+CAST(#CurrentFrame AS VARCHAR)+ ' THEN Choice ELSE NULL END) AS Choice_'+CAST(#CurrentFrame AS VARCHAR)
+ ', MAX(CASE WHEN RowNumber ='+CAST(#CurrentFrame AS VARCHAR)+ ' THEN Description ELSE NULL END) AS Description_'+CAST(#CurrentFrame AS VARCHAR)
+ ', MAX(CASE WHEN RowNumber ='+CAST(#CurrentFrame AS VARCHAR)+ ' THEN [DateTime] ELSE NULL END) AS DateTime_'+CAST(#CurrentFrame AS VARCHAR)
SET #SQL = #SQL + #ColumnSQL
SET #CurrentFrame = #CurrentFrame + 1
END
SET #SQL = #SQL + ' FROM ( SELECT UserId,Frame,Choice,Description,[DateTime], ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY [DateTime]) AS RowNumber FROM #FrameChoices) T GROUP BY T.UserId'
PRINT #SQL
-- This generated SQL then can be executed by
EXEC(#SQL)
-- OR
EXEC SP_EXECUTESQL(#SQL)
-- Sample SQL generated from above query
SELECT UserId, MAX(CASE WHEN RowNumber =1 THEN Frame ELSE NULL END) AS Frame_1, MAX(CASE WHEN RowNumber =1 THEN Choice ELSE NULL END) AS Choice_1, MAX(CASE WHEN RowNumber =1 THEN Description ELSE NULL END) AS Description_1, MAX(CASE WHEN RowNumber =1 THEN [DateTime] ELSE NULL END) AS DateTime_1, MAX(CASE WHEN RowNumber =2 THEN Frame ELSE NULL END) AS Frame_2, MAX(CASE WHEN RowNumber =2 THEN Choice ELSE NULL END) AS Choice_2, MAX(CASE WHEN RowNumber =2 THEN Description ELSE NULL END) AS Description_2, MAX(CASE WHEN RowNumber =2 THEN [DateTime] ELSE NULL END) AS DateTime_2 FROM ( SELECT UserId,Frame,Choice,Description,[DateTime], ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY [DateTime]) AS RowNumber FROM #FrameChoices) T GROUP BY T.UserId
What you want is the Pivot Table functionality of SQL Server
http://msdn.microsoft.com/en-us/library/ms177410(SQL.90).aspx

Dynamic SQL to generate column names?

I have a query where I'm trying pivot row values into column names and currently I'm using SUM(Case...) As 'ColumnName' statements, like so:
SELECT
SKU1,
SUM(Case When Sku2=157 Then Quantity Else 0 End) As '157',
SUM(Case When Sku2=158 Then Quantity Else 0 End) As '158',
SUM(Case When Sku2=167 Then Quantity Else 0 End) As '167'
FROM
OrderDetailDeliveryReview
Group By
OrderShipToID,
DeliveryDate,
SKU1
The above query works great and gives me exactly what I need. However, I'm writing out the SUM(Case... statements by hand based on the results of the following query:
Select Distinct Sku2 From OrderDetailDeliveryReview
Is there a way, using T-SQL inside a stored procedure, that I can dynamically generate the SUM(Case... statements from the Select Distinct Sku2 From OrderDetailDeliveryReview query and then execute the resulting SQL code?
Having answered a lot of these over the years by generating dynamic pivot SQL from the metadata, have a look at these examples:
SQL Dynamic Pivot - how to order columns
SQL Server 2005 Pivot on Unknown Number of Columns
What SQL query or view will show "dynamic columns"
How do I Pivot on an XML column's attributes in T-SQL
How to apply the DRY principle to SQL Statements that Pivot Months
In your particular case (using the ANSI pivot instead of SQL Server 2005's PIVOT feature):
DECLARE #template AS varchar(max)
SET #template = 'SELECT
SKU1
{COLUMN_LIST}
FROM
OrderDetailDeliveryReview
Group By
OrderShipToID,
DeliveryDate,
SKU1
'
DECLARE #column_list AS varchar(max)
SELECT #column_list = COALESCE(#column_list, ',') + 'SUM(Case When Sku2=' + CONVERT(varchar, Sku2) + ' Then Quantity Else 0 End) As [' + CONVERT(varchar, Sku2) + '],'
FROM OrderDetailDeliveryReview
GROUP BY Sku2
ORDER BY Sku2
Set #column_list = Left(#column_list,Len(#column_list)-1)
SET #template = REPLACE(#template, '{COLUMN_LIST}', #column_list)
EXEC (#template)
I know that SO search engine is not perfect, but your question has been answered in SQL Server PIVOT Column Data.
Also see Creating cross tab queries and pivot tables in SQL.
Why do this using hard coded column names when you can pull all this dynamically from any table?
Using UNPIVOT and COALESCE, I can dynamically pull a list of columns from any table and associated column values for any record in a record listing and combine them in a list of column names with values by row. Here is the code. Just drop in your database and table name. The column/value table will be generated for you in SQL Server. Keep in mind, to get a shared column of values for the columns you want to convert to sql variant or text strings. But a great way to get a sample column list of values with matching column names and types with our while loops or cursors. Its pretty fast:
-- First get a list of all known columns in your database, dynamically...
DECLARE #COLUMNS nvarchar(max)
SELECT #COLUMNS =
CASE
WHEN A.DATA_TYPE = 'nvarchar' OR A.DATA_TYPE = 'ntext' THEN
COALESCE(#COLUMNS + ',','') + 'CAST(CONVERT(nvarchar(4000),['+A.[name]+']) AS sql_variant) AS ['+A.[name]+']'
WHEN A.DATA_TYPE = 'datetime' OR A.DATA_TYPE = 'smalldatetime' THEN
COALESCE(#COLUMNS + ',','') + 'CAST(CONVERT(nvarchar,['+A.[name]+'],101) AS sql_variant) AS ['+A.[name]+']'
ELSE
COALESCE(#COLUMNS + ',','') + 'CAST(['+A.[name]+'] AS sql_variant) AS ['+A.[name]+']'
END
FROM
(
SELECT
A.name,
C.DATA_TYPE
FROM YOURDATABASENAME.dbo.syscolumns A
INNER JOIN YOURDATABASENAME.dbo.sysobjects B ON B.id = A.id
LEFT JOIN
(
SELECT
COLUMN_NAME,
DATA_TYPE
FROM YOURDATABASENAME.INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'YOURTABLENAME'
) C ON C.COLUMN_NAME = A.name
WHERE B.name = 'YOURTABLENAME'
AND C.DATA_TYPE <> 'timestamp'
) A
-- Test that the formatted columns list is returned...
--SELECT #COLUMNS
-- This gets a second string list of all known columns in your database, dynamically...
DECLARE #COLUMNS2 nvarchar(max)
SELECT #COLUMNS2 = COALESCE(#COLUMNS2 + ',','') + '['+A.[name]+']'
FROM
(
SELECT
A.name,
C.DATA_TYPE
FROM YOURDATABASENAME.dbo.syscolumns A
INNER JOIN YOURDATABASENAME.dbo.sysobjects B ON B.id = A.id
LEFT JOIN
(
SELECT
COLUMN_NAME,
DATA_TYPE
FROM YOURDATABASENAME.INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'YOURTABLENAME'
) C ON C.COLUMN_NAME = A.name
WHERE B.name = 'YOURTABLENAME'
AND C.DATA_TYPE <> 'timestamp'
) A
-- Test that the formatted columns list is returned...
--SELECT #COLUMNS2
-- Now plug in the list of the dynamic columns list into an UNPIVOT to get a Column Name / Column Value list table...
DECLARE #sql nvarchar(max)
SET #sql =
'
SELECT
ColumnName,ColumnValue
FROM
(
SELECT
'+#COLUMNS+'
FROM YOURDATABASENAME.dbo.YOURTABLENAME
WHERE CHANGE_ID IN (SELECT ChangeId FROM YOURDATABASENAME.dbo.OperatorProcess WHERE OperatorProcessID = 3)
) AS SourceTable
UNPIVOT
(
ColumnValue FOR ColumnName IN ('+#COLUMNS2+')
) AS PivotTable
'
EXEC (#sql)
-- Darshankar Madhusudan i can do dynamic columnheading table easly...
--thanks
declare #incr int = 1,
#col int,
#str varchar(max),
#tblcrt varchar(max),
#insrt varchar(max),
set #tblcrt = 'DECLARE #Results table ('
set #str = ''
set #insrt = ''
select #col = max(column_id) From tempdb.sys.all_columns where object_id = object_id('tempdb.dbo.#aaa')
while #incr <= #col
BEGIN
SELECT #STR = #STR +case when #incr = 1 then '''' else ',''' end +rtrim(ltrim(NAME))+'''' FROM TEMPDB.SYS.ALL_COLUMNS WHERE OBJECT_ID = OBJECT_ID('TEMPDB.DBO.#AAA') and column_id = #incr
set #tblcrt = #tblcrt + case when #incr = 1 then '' else ',' end + 'Fld'+CAST(#incr as varchar(3)) +' varchar(50)'
set #insrt = #insrt + case when #incr = 1 then '' else ',' end + 'Fld'+CAST(#incr as varchar(3))
SET #INCR = #INCR + 1
END
set #tblcrt = #tblcrt + ')'
set #insrt = 'insert into #Results('+#insrt+') values (' + #STR +')'
set #tblcrt = #tblcrt+ ';' + #insrt + 'select * from #Results '
exec(#tblcrt)