SQL存储过程,将行输出为摘要列

时间:2011-12-02 22:35:36

标签: sql stored-procedures macros

使用SQL 2005 这是我的SQL结果的样子

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
...

我的客户希望结果看起来像这样

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-..|

所有参与者的回复都在一行中。对于结果集的每一行,基本上需要另一组Frame / Choice Description / DateTime。

这些是调查结果,但调查类型中有一位参与者可能已经回过头并改变了他们的答案5次。因此,每个UserID的Frame / Choice Description / DateTime的数量将不同。

我知道我应该使用存储过程(或者甚至是excel宏),但我对这两者都是全新的。任何指导表示赞赏。这是我的SQL查询

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

<小时/> 的 !!更新!! 完整的工作解决方案和测试代码
- 样本数据准备 将@FrameChoices声明为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

- 动态SQL准备

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

- 然后可以通过

执行生成的SQL
EXEC(@SQL)
 -- OR
EXEC SP_EXECUTESQL(@SQL)

- 从上面的查询生成的示例SQL

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

2 个答案:

答案 0 :(得分:1)

如果是SQL 2005或ABove,您可以尝试使用pivot。

如果是SQL 2000,则使用Group By和Case的组合。

SELECT GC1,
       GC2,
       MAX(CASE WHEN CONDITION1 THEN Value1 ELSE Value2 END) AS DerivedColumn
FROM Table1
GROUP BY GC1, GC2

参考文献: SQL Server PIVOT and UNPIVOT

Pivot with Dynamic Column

Stack Overflow Pivot Question

[解决]

- 样本数据准备

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

- 动态SQL准备

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

- 然后可以通过

执行生成的SQL
EXEC(@SQL)
 -- OR
EXEC SP_EXECUTESQL(@SQL)

- 从上面的查询生成的示例SQL

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

答案 1 :(得分:0)

您想要的是SQL Server的数据透视表功能

http://msdn.microsoft.com/en-us/library/ms177410(SQL.90).aspx