SQL将行数据转置为列

时间:2017-07-19 03:24:46

标签: sql sql-server pivot

我正在寻找一种纯SQL方式(SQL Server 2012,如果重要的话)将行数据转换为列。我试过搜索这个,但是找不到我想要转换的数据格式的东西,可能是因为我的SQL知识非常基础。

我的输入数据是从我们的JIRA服务器中提取的版本名称和故事点列表,以及提取日期。我试图使用的表实际上包含来自许多不同项目的提取,尽管我从这些示例中排除了ProjectName列。

输入数据:

Version     Date        StoryPoints
1.0         2017-01-01  10
1.0         2017-02-01  10
1.0         2017-03-01  15
1.0         2017-04-01  15
2.0         2017-01-01  10
2.0         2017-02-01  10
2.0         2017-03-01  10
2.0         2017-04-01  10
3.0         2017-01-01  5
3.0         2017-02-01  5
3.0         2017-03-01  5
3.0         2017-04-01  5
Completed   2017-01-01  0
Completed   2017-02-01  5
Completed   2017-03-01  15
Completed   2017-04-01  28

我们需要以下面任一格式生成一个表格,用于在Confluence wiki中创建“燃尽”图表。由于每个项目可以具有不同的版本名称,因此我们无法对下面的任何列名称进行硬编码(尽管“已完成”将存在于所有项目中)。

此外,即使我们将标准化类似于示例中的日期,我也不希望将任何日期值硬编码到查询中。

输出格式#1:

Date        1.0 2.0 3.0 Completed
2017-01-01  10  10  5   0
2017-02-01  10  10  5   5
2017-03-01  15  10  5   15
2017-04-01  15  10  5   28

我认识到以这种方式构建数据可能很困难,因此也可以使用以下输出格式,我也可以在Confluence中绘制图表(虽然它不像上面的格式那样直观)。

输出格式#2:

Versions    2017-01-01  2017-02-01  2017-03-01  2017-04-01
1.0         10          10          15          15
2.0         10          10          10          10
3.0         5           5           5           5
Completed   0           5           15          28

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:2)

SQL Server 2012要求您将要转移的维度之一硬编码到PIVOT query中。

解决这个问题的一种方法是构建并执行动态query string

答案 1 :(得分:2)

正如刘星洲所说,我想到了这一点。

来源:

            IF ( OBJECT_ID('tempdb..#TMPtbl') IS NOT NULL )
                BEGIN
                    DROP TABLE #TMPtbl
                END


            CREATE TABLE #TMPtbl
                (
                  Id INT IDENTITY(1, 1)
                         PRIMARY KEY ,
                  [Version] VARCHAR(10) ,
                  [Date] DATETIME ,
                  StoryPoints INT
                )

            INSERT  INTO #TMPtbl
                    ( Version, Date, StoryPoints )
            VALUES  ( '1.0', '2017-01-01', 10 ),
                    ( '1.0', '2017-02-01', 10 ),
                    ( '1.0', '2017-03-01', 15 ),
                    ( '1.0', '2017-04-01', 15 ),
                    ( '2.0', '2017-01-01', 10 ),
                    ( '2.0', '2017-02-01', 10 ),
                    ( '2.0', '2017-03-01', 10 ),
                    ( '2.0', '2017-04-01', 10 ),
                    ( '3.0', '2017-01-01', 5 ),
                    ( '3.0', '2017-02-01', 5 ),
                    ( '3.0', '2017-03-01', 5 ),
                    ( '3.0', '2017-04-01', 5 ),
                    ( 'Completed', '2017-01-01', 0 ),
                    ( 'Completed', '2017-02-01', 5 ),
                    ( 'Completed', '2017-03-01', 15 ),
                    ( 'Completed', '2017-04-01', 28 )

使用STUFFFOR XML,您可以动态获取列

                DECLARE @StrColVer NVARCHAR(MAX) = STUFF(( SELECT DISTINCT
                                                                    ', '
                                                                    + QUOTENAME(CAST(t.[Version] AS VARCHAR(154)))
                                                           FROM     #TMPtbl t
                                                         FOR
                                                           XML PATH('')
                                                         ), 1, 2, '')


                DECLARE @StrColSUmVer NVARCHAR(MAX) = STUFF(( SELECT DISTINCT
                                                                        ', ' + 'SUM('
                                                                        + QUOTENAME(CAST(t.[Version] AS VARCHAR(154)))
                                                                        + ') '
                                                                        + QUOTENAME(CAST(t.[Version] AS VARCHAR(154)))
                                                              FROM      #TMPtbl t
                                                            FOR
                                                              XML PATH('')
                                                            ), 1, 2, '')

                DECLARE @StrColDate NVARCHAR(MAX) = STUFF(( SELECT DISTINCT
                                                                    ', '
                                                                    + QUOTENAME(FORMAT(t.Date,
                                                                              'yyyy-MM-dd'))
                                                            FROM    #TMPtbl t
                                                          FOR
                                                            XML PATH('')
                                                          ), 1, 2, '')

                DECLARE @StrColSumDate NVARCHAR(MAX) = STUFF(( SELECT DISTINCT
                                                                        ', ' + 'SUM('
                                                                        + QUOTENAME(FORMAT(t.Date,
                                                                              'yyyy-MM-dd'))
                                                                        + ') '
                                                                        + QUOTENAME(FORMAT(t.Date,
                                                                              'yyyy-MM-dd'))
                                                               FROM     #TMPtbl t
                                                             FOR
                                                               XML PATH('')
                                                             ), 1, 2, '')

然后PivotExecute将其作为命令查询字符串。

DECLARE @SQL1 NVARCHAR(MAX)  = N'SELECT [Date],
        ' + @StrColSUmVer + '
                FROM (
                SELECT * FROM #TMPtbl

        )P
    PIVOT (
            SUM(StoryPoints) FOR Version IN (' + @StrColVer + ')
    )PVT
    GROUP BY pvt.[Date]'



DECLARE @SQL2 NVARCHAR(MAX)  = N'SELECT [Version],
        ' + @StrColSumDate + '
                FROM (
                SELECT * FROM #TMPtbl

        )P
    PIVOT (
            SUM(StoryPoints) FOR dATE IN (' + @StrColDate + ')
    )PVT
    GROUP BY pvt.[Version]'

EXEC(@SQL1)
EXEC(@SQL2)

结果

    Date                    1.0         2.0         3.0         Completed
    ----------------------- ----------- ----------- ----------- -----------
    2017-01-01 00:00:00.000 10          10          5           0
    2017-02-01 00:00:00.000 10          10          5           5
    2017-03-01 00:00:00.000 15          10          5           15
    2017-04-01 00:00:00.000 15          10          5           28

    (4 row(s) affected)


    Version    2017-01-01  2017-02-01  2017-03-01  2017-04-01
    ---------- ----------- ----------- ----------- -----------
    1.0        10          10          15          15
    2.0        10          10          10          10
    3.0        5           5           5           5
    Completed  0           5           15          28

    (4 row(s) affected)