I am trying to return a default value if no such record exists for the given parameters. Here's the sql query:
DECLARE #List VARCHAR(max)
DECLARE #date VARCHAR(max)
SET #List = '''4401366'',''3115880'''
SET #date = '''2018-02-09 00:00:00.000'''
DECLARE #SQL NVARCHAR(max)
SET #SQL = N'
select EmpNo, attendanceStatus =
CASE
WHEN AttDate is null then ''false''
WHEN max(AttTimeIn) is null and max(AttTimeOut) is null THEN ''false''
WHEN max(AttTimeIn) is not null and max(AttTimeOut) is not null then(case when (max(AttTimeIn) < max(AttTimeOut)) then ''false'' else ''true'' end)
WHEN max(AttTimeIn) is not null and max(AttTimeOut) is null THEN ''true''
else ''false''
end
from tablename
where empNo in (' +#list+ ') AND AttDate = ('+ #date +')
group by EmpNo, AttDate'
EXEC sp_executesql #SQL
To be more specific, i want attendanceStatus to return false in case no such record exists for the given date (for each employee). How can I achieve this?
I believe you need something like this, but without data it is difficult to test:
SET #SQL = N'
SELECT T0.EmpNo
, attendanceStatus = CASE
WHEN T1.empNo is null
THEN ''false''
WHEN max(T1.AttTimeIn) is null and max(T1.AttTimeOut) is null
THEN ''false''
WHEN max(T1.AttTimeIn) is not null and max(T1.AttTimeOut) is not null
THEN(CASE WHEN (max(T1.AttTimeIn) < max(T1.AttTimeOut))
THEN ''false'' else ''true'' END)
WHEN max(T1.AttTimeIn) is not null and max(T1.AttTimeOut) is null
THEN ''true''
ELSE ''false''
END
FROM tablename T0
LEFT JOIN tablename T1
ON T1.empNo = T0.empNo
AND T1.AttDate = ('+ #date +')
WHERE T0.empNo in (' +#list+ ')
GROUP BY T0.EmpNo
, T1.AttDate
'
you can try this.
DECLARE #List VARCHAR(max)
DECLARE #date VARCHAR(max)
SET #List = '''4401366'',''3115880'''
SET #date = '''2018-02-09 00:00:00.000'''
DECLARE #SQL NVARCHAR(max)
SET #SQL = N'
select EmpNo, attendanceStatus =
CASE WHEN AttDate = ('+ #date +') THEN
CASE
WHEN max(AttTimeIn) is null and max(AttTimeOut) is null THEN ''false''
WHEN max(AttTimeIn) is not null and max(AttTimeOut) is not null then(case when (max(AttTimeIn) < max(AttTimeOut)) then ''false'' else ''true'' end)
WHEN max(AttTimeIn) is not null and max(AttTimeOut) is null THEN ''true''
ELSE ''false''
END
ELSE ''false'' END
from tablename
where empNo in (' +#list+ ')
group by EmpNo, AttDate'
EXEC sp_executesql #SQL
this should work
DECLARE #List VARCHAR(max)
DECLARE #date VARCHAR(max)
SET #List = '''4401366'',''3115880'''
SET #date = '''2018-02-09 00:00:00.000'''
DECLARE #SQL NVARCHAR(max)
SET #SQL = N'
--check if employee exists
with empTable as (
SELECT DISTINCT EmpNo
FROM tablename
WHERE empNo in (' +#list+ '))
select Et.EmpNo, attendanceStatus =
CASE
WHEN T.AttDate is null then ''false''
WHEN max(T.AttTimeIn) is null and max(T.AttTimeOut) is null THEN ''false''
WHEN max(T.AttTimeIn) is not null and max(T.AttTimeOut) is not null then(case when (max(T.AttTimeIn) < max(T.AttTimeOut)) then ''false'' else ''true'' end)
WHEN max(T.AttTimeIn) is not null and max(T.AttTimeOut) is null THEN ''true''
else ''false''
end
from
empTable eT
LEFT JOIN tablename T ON
et.EmpNo=T.EmpNo
where T.AttDate = ('+ #date +')
group by et.EmpNo, T.AttDate'
EXEC sp_executesql #SQL
I have rewritten your code, simplified your case statement and removed some code
AttDate is null then 'false'
AttDate will never be null because it is included in the where clause
I also changed the data type for #date and made it into a parameterized query for date. Your script is still prone to sql injection because of #List. This can be avoided by splitting it into a table.
I am not sure what you want to replace with a default value. But here is the improved script:
DECLARE #List VARCHAR(max)
DECLARE #date DATE
SET #List = '''4401366'',''3115880'''
SET #date = '2018-02-09'
DECLARE #SQL NVARCHAR(max)
SET #SQL = N'
SELECT coalesce(EmpNo, ''default'') EmpNo,
CASE WHEN i is not null and (i >= o or o is null) THEN ''true'' ELSE ''false'' END
FROM
(
SELECT
Empno,
max(AttTimeIn) over (partition by EmpNo) i,
max(AttTimeOut) over (partition by EmpNo)o
FROM tablename
WHERE empNo in (' +#list+ ') AND AttDate = #date
GROUP BY EmpNo, AttDate
) x
GROUP BY EmpNo'
EXEC sp_executesql #SQL, N'#date date', #date
Related
How to make sum of blank values in SQL Server?
I tried with following but returns null
Declare #val varchar
Declare #columns varchar(20)
declare #sql varchar(200)
set #columns= 'branch'
set #sql = 'select ' + #val +'= sum(case when #columns = '''' then 1 else 0 end)
from dbo.companies'
exec(#sql)
select #val
I need a dynamic SQL statement because values will be returned from stored procedure for each column.
Total stab in the dark, but I think what you're after is:
DECLARE #Count int, #Column sysname;
DECLARE #SQL nvarchar(MAX);
SET #Column = N'SomeColumnName';
SET #SQL = N'SELECT #Count = COUNT(CASE ' + QUOTENAME(#Column) + N' WHEN '''' THEN 1 END) FROM dbo.companies;';
EXEC sp_excutesql #SQL, N'#Count int OUTPUT',#Count = #Count OUTPUT;
SELECT #Count;
Edit: Note that that '' and NULL are not the same value; something that you seem to be unaware of considering you where concatenating a variable (#Val of the datatype varchar(1)) with the value NULL to a literal string. NULL + {expr} = NULL. If you want to count rows with NULL, not a blank string is IS NULL (and you'll need to move the WHEN).
I have a WHERE IN ('') statement, if nothing is entered, how do I select ALL?
Depend on database you are working. But you can do something like this:
-- SQLServer
DECLARE #in varchar(20) = ''
SELECT * FROM <table> WHERE (#in = '' or <field> IN (''))
-- OR
IF #in = ''
SELECT * FROM <table>
ELSE
SELECT * FROM <table> WHERE <field> IN ('')
If you want to select all values, if there is no value for a variable, then just use ISNULL function( will have an index scan):
WHERE yourField IN (ISNULL(#yourNullVariable, yourField))
Let me show an example:
DECLARE #table TABLE
(
FooDate DATETIME,
FooBar VARCHAR(50)
)
INSERT INTO #table
(
FooDate,
FooBar
)
VALUES
( GETDATE(), -- FooDate - datetime
'A' -- FooBar - varchar(50)
)
, ('2019-02-18', 'AA')
, ('2019-01-18', 'B')
, ('2019-01-18', 'BB')
DECLARE #fooVariable VARCHAR(50) = NULL
SELECT * FROM #table tbl
WHERE tbl.FooBar = ISNULL(#fooVariable, tbl.FooBar)
OUTPUT:
FooDate FooBar
2019-02-18 16:37:20.920 A
2019-02-18 00:00:00.000 AA
2019-01-18 00:00:00.000 B
2019-01-18 00:00:00.000 BB
Or use dynamic SQL( will have an index seek):
DECLARE #fooVariable VARCHAR(50) = NULL
DECLARE #sql NVARCHAR(max), #where NVARCHAR(255);
SET #sql = N'SELECT * FROM Yourtable tbl'
IF #fooVariable IS NOT NULL
BEGIN
SET #where = ' tbl.FooBar = ' + #fooVariable
SET #sql = CONCAT(#sql, #where)
END
EXEC SP_EXECUTESQL #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];
I've got a stored procedure that is taking data from one table, running through my dynamic pivot stored procedure, and outputting into the page. The problem is, there is a substantial number of null entries. When I process this data on the page, I'm needing to add each of the fuel quantities per TerminalID. The issue arises when it hits the null entries. I don't want to have the procedure read through every row and column to convert null to 0, and was hoping to do so in the SP.
For Testing, I've made this script:
DECLARE #QUERY NVARCHAR(MAX)
, #Soucecolumn VARCHAR(MAX)
, #BeginningDate VARCHAR(MAX)
, #EndingDate VARCHAR(MAX)
, #CompanyID VARCHAR(2)
SET NOCOUNT ON;
SET #BeginningDate = CONVERT(VARCHAR(30), CAST('2004-01-01' AS DATE));
SET #EndingDate = CONVERT(VARCHAR(30), CAST('2007-01-01' AS DATE));
SET #CompanyID = CONVERT(INT, '2');
SET #Soucecolumn = STUFF((
SELECT DISTINCT ', \[' + CAST(FuelTypeID AS VARCHAR(4)) + '\]'
FROM tt_Manifest_Fuel_Distribution
FOR XML PATH ('')), 1, 1, '')
SET #QUERY = '(
SELECT ManifestID, TerminalID, ' + #Soucecolumn + '
FROM (
SELECT mfd.ManifestID, m.TerminalID, mfd.FuelTypeID, mfd.FuelQuantity
FROM tt_Manifest_Fuel_Distribution mfd, tt_Terminals t, tt_Fuel_Types ft, tt_Manifests m
WHERE mfd.FuelTypeID=ft.FuelTypeID
AND m.ManifestID=mfd.ManifestID
AND m.CompanyID= ' + #CompanyID + '
AND m.ManifestInsertDate BETWEEN ''' + #BeginningDate + ''' AND ''' + #EndingDate +
'''
) up
PIVOT (
MAX(FuelQuantity) FOR \[FuelTypeID\] IN (' + #Soucecolumn + ')
) AS pvt)'
EXEC sp_executesql #QUERY
Sample data is:
>ManifestID TerminalID 3 6 4 2 1 5
>417 1 NULL NULL NULL NULL NULL 2478
>421 1 NULL NULL NULL NULL 3458 NULL
>508 1 NULL NULL NULL NULL NULL 2471
>826 1 NULL NULL NULL NULL NULL 7464
>832 1 NULL NULL NULL NULL 3482 NULL
>833 1 1001 NULL NULL NULL 1492 NULL
>844 1 NULL NULL NULL NULL 2498 NULL
>870 1 NULL NULL NULL NULL 5991 2503
>872 1 NULL NULL NULL NULL 3494 NULL
>2 2 NULL NULL 5514 NULL NULL 2505
>43 2 NULL NULL NULL NULL 7011 NULL
>46 2 1005 NULL NULL NULL 5007 2510
>60 2 NULL NULL 3502 NULL NULL 4513
>63 2 NULL NULL 4505 NULL NULL 3008
>69 2 NULL NULL 4008 NULL 4508 NULL
>78 2 1007 NULL NULL NULL 5022 NULL
>79 2 NULL NULL 2505 NULL NULL NULL
I've tried placing ISNULL(,0) around the mfd.FuelQuantity, and around the #Sourcecolumn. mfd.FuelQuantiity seemed to have no change, while the #Sourcecolumn error-ed out claiming that the ISNull() required 2 arguments.
Am I looking at this in the wrong way?
I'd strongly suggest moving away from deprecated implicit joins.
You need to incorporate ISNULL() into each item in the #sourcecolumn list in the SELECT clause. The reason it threw an error is because your entire list of columns was wrapped in one statement: ISNULL(col1,col2,col3...,0) you need ISNULL(col1,0),ISNULL(col2,0)...
I'd suggest making a separate sourcecolumn variable for use in your SELECT.
Something like:
SET #Sourcecolumn2 = STUFF((SELECT distinct ',ISNULL(\[' + CAST(FuelTypeID as varchar(4)) + ',0)\]as '+ CAST(FuelTypeID as varchar(4)) +' FROM tt_Manifest_Fuel_Distribution
FOR XML PATH('')),1,1,'')
So ultimately:
![Declare #QUERY NVARCHAR(MAX),
#Soucecolumn VARCHAR(MAX),
#Sourcecolumn2 VARCHAR(MAX),
#BeginningDate VARCHAR(MAX),
#EndingDate VARCHAR(MAX),
#CompanyID VARCHAR(2)
SET NOCOUNT ON;
SET #BeginningDate = convert(varchar(30), cast('2004-01-01' as date));
SET #EndingDate = convert(varchar(30), cast('2007-01-01' as date));
SET #CompanyID = convert(int, '2');
SET #Soucecolumn = STUFF((SELECT distinct ', \[' + CAST(FuelTypeID as varchar(4)) + '\]' FROM tt_Manifest_Fuel_Distribution
FOR XML PATH('')),1,1,'');
SET #Sourcecolumn2 = STUFF((SELECT distinct ',ISNULL(\[' + CAST(FuelTypeID as varchar(4)) + ',0)\] as '+ CAST(FuelTypeID as varchar(4))+' FROM tt_Manifest_Fuel_Distribution
FOR XML PATH('')),1,1,'');
SET #QUERY = '(SELECT ManifestID, TerminalID, ' + #Sourcecolumn2 + ' FROM (
SELECT mfd.ManifestID, m.TerminalID, mfd.FuelTypeID, mfd.FuelQuantity
FROM tt_Manifest_Fuel_Distribution mfd, tt_Terminals t, tt_Fuel_Types ft, tt_Manifests m
WHERE mfd.FuelTypeID=ft.FuelTypeID
AND m.ManifestID=mfd.ManifestID
AND m.CompanyID= ' + #CompanyID + '
AND m.ManifestInsertDate BETWEEN ''' + #BeginningDate + ''' AND ''' + #EndingDate +
''' ) up PIVOT (MAX(FuelQuantity) FOR \[FuelTypeID\] IN (' + #Soucecolumn + ')) AS pvt)'
exec sp_executesql #QUERY][1]
Consider the below table
Here is the sample data
SELECT * INTO #TEMP
FROM
(
SELECT '01/JAN/2014' [DATE],'A' NAME,100 MARKS
UNION ALL
SELECT '02/JAN/2014' [DATE],'A' NAME,120
UNION ALL
SELECT '02/JAN/2014' [DATE],'B' NAME,130
UNION ALL
SELECT '03/JAN/2014' [DATE],'B' NAME,115
UNION ALL
SELECT '01/JAN/2014' [DATE],'C' NAME,123
UNION ALL
SELECT '01/JAN/2014' [DATE],'C' NAME,134
UNION ALL
SELECT '03/JAN/2014' [DATE],'C' NAME,146
UNION ALL
SELECT '04/JAN/2014' [DATE],'C' NAME,149
)TAB
Now select the distinct names to a variable for pivot
DECLARE #cols NVARCHAR (MAX)
SET #cols = SUBSTRING((SELECT DISTINCT ',['+NAME+']'
FROM #TEMP GROUP BY NAME FOR XML PATH('')),2,8000)
Now you need another variable to apply the NULL to zero logic
DECLARE #NulltoZeroCols NVARCHAR (MAX)
SET #NulltoZeroCols = SUBSTRING((SELECT DISTINCT ',ISNULL(['+NAME+'],0) AS ['+NAME+']'
FROM #TEMP GROUP BY NAME FOR XML PATH('')),2,8000)
Now pivot the query using both variables
DECLARE #query NVARCHAR(MAX)
SET #query = 'SELECT DATE,' + #NulltoZeroCols + ' FROM
(
SELECT [DATE],NAME,MARKS FROM #TEMP
) x
PIVOT
(
SUM(MARKS)
FOR [NAME] IN (' + #cols + ')
) p
;'
EXEC SP_EXECUTESQL #query
Finally your result is as below
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