使用 PIVOT/UNPIVOT 将行转换为列

Posted

技术标签:

【中文标题】使用 PIVOT/UNPIVOT 将行转换为列【英文标题】:Using PIVOT/UNPIVOT to convert rows to columns 【发布时间】:2010-09-10 15:36:05 【问题描述】:

我一直在阅读关于 PIVOT 和 UNPIVOT 的内容,但未能正确格式化结果以呈现数据。这是我的源表:

StepID         |      ShortDesc     |     Type_1        |      ar1      |    ar2
   1                  ShortDesc1            10                11.11         11.01
   2                  ShortDesc2            20                22.22         22.02
   3                  ShortDesc3            30                33.33         33.03
   4                  ShortDesc4            40                44.44         44.04
   5                  ShortDesc5            50                55.55         55.05           

这是我想要达到的结果:

 |      Step1       |       Step2     |      Step3     |     Step4      |     Step5
      ShortDesc1         ShortDesc2       ShortDesc3      ShortDesc4        ShortDesc5
         10                 20                30              40               50
        11.11             22.22             33.33            44.44           55.55
        11.01             22.02             33.03            44.04           55.05

这是我尝试过的最新方法,当然没用:

DROP TABLE ProductionTest
CREATE TABLE ProductionTest (StepID int, ShortDesc nvarchar(25), Type_1 int, ar1 real, ar2 real)
INSERT INTO ProductionTest  VALUES (1, 'Short Desc 1', 10, 11.11, 11.01)
INSERT INTO ProductionTest  VALUES (2, 'Short Desc 2', 20, 22.22, 22.02)
INSERT INTO ProductionTest  VALUES (3, 'Short Desc 3', 30, 33.33, 33.03)
INSERT INTO ProductionTest  VALUES (4, 'Short Desc 4', 40, 44.44, 44.04)
INSERT INTO ProductionTest  VALUES (5, 'Short Desc 5', 50, 55.55, 55.05)

SELECT * FROM ProductionTest

SELECT [1]as Step1, [2] as Step2, [3]as Step3, [4]as Step4, [5]as Step5
FROM     ( SELECT [StepID], ShortDesc, Type_1, ar1, ar2
           FROM   ProductionTest) p 
PIVOT (MAX(ShortDesc)
                     FOR StepID IN ([1], [2], [3], [4], [5])
       ) AS pvt

感谢您的帮助!

【问题讨论】:

【参考方案1】:

Pivot 不会旋转整个表格。我认为您需要类似的东西

SELECT [1]as Step1, [2] as Step2, [3]as Step3, [4]as Step4, [5]as Step5
FROM     ( SELECT [StepID], ShortDesc
           FROM   ProductionTest) p 
PIVOT (MAX(ShortDesc)
                     FOR StepID IN ([1], [2], [3], [4], [5])
       ) AS pvt

UNION ALL

SELECT [1]as Step1, [2] as Step2, [3]as Step3, [4]as Step4, [5]as Step5
FROM     ( SELECT [StepID], CAST(Type_1 AS nvarchar(25)) AS Type_1
           FROM   ProductionTest) p 
PIVOT (MAX(Type_1)
                     FOR StepID IN ([1], [2], [3], [4], [5])
       ) AS pvt

UNION ALL

SELECT [1]as Step1, [2] as Step2, [3]as Step3, [4]as Step4, [5]as Step5
FROM     ( SELECT [StepID], CAST(ar1 AS nvarchar(25)) AS ar1
           FROM   ProductionTest) p 
PIVOT (MAX(ar1)
                     FOR StepID IN ([1], [2], [3], [4], [5])
       ) AS pvt

UNION ALL

SELECT [1]as Step1, [2] as Step2, [3]as Step3, [4]as Step4, [5]as Step5
FROM     ( SELECT [StepID], CAST(ar2 AS nvarchar(25)) AS ar2
           FROM   ProductionTest) p 
PIVOT (MAX(ar2)
                     FOR StepID IN ([1], [2], [3], [4], [5])
       ) AS pvt

【讨论】:

谢谢,这行得通,虽然确实比我最初认为的要复杂得多。你的权利,我真正需要做的是“翻转”桌子。这给了我一个很好的起点。再次感谢!! 实际上,如果可以的话,还有一个后续问题。使这种动态与静态变得多么困难。我最初的想法是创建一个数据库视图和/或存储过程。你怎么看?【参考方案2】:

根据您希望通过动态版本执行此操作的评论。您可以将 Martin 的版本用于静态版本,但如果您想要动态版本,这意味着 StepID's 的数量会发生变化,那么您可以执行以下操作:

DECLARE @cols AS NVARCHAR(MAX),
    @colsAlias AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX);

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(StepID) 
                    from ProductionTest
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

SELECT @colsAlias = STUFF((SELECT DISTINCT ',' + QUOTENAME(p.StepID) + ' AS ' + QUOTENAME('Step' + Cast(p1.StepID as varchar(10)))  
    FROM ProductionTest p INNER JOIN ProductionTest p1 ON p.StepID = p1.StepID
    FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')


set @query = 'SELECT ' + @colsAlias + ' from 
             (
                 select [StepID], ShortDesc
                 FROM   ProductionTest
            ) x
            pivot 
            (
                MAX(ShortDesc)
                for stepId in (' + @cols + ')
            ) p 
            UNION ALL
            SELECT ' + @colsAlias + ' from 
             (
                 select [StepID], CAST(Type_1 AS nvarchar(25)) AS Type_1
                 FROM   ProductionTest
            ) x
            pivot 
            (
                MAX(Type_1)
                for stepId in (' + @cols + ')
            ) p 
            UNION ALL
            SELECT ' + @colsAlias + ' from 
             (
                 select [StepID], CAST(ar1 AS nvarchar(25)) AS ar1
                 FROM   ProductionTest
            ) x
            pivot 
            (
                MAX(ar1)
                for stepId in (' + @cols + ')
            ) p 
            UNION ALL
            SELECT ' + @colsAlias + ' from 
             (
                 select [StepID], CAST(ar2 AS nvarchar(25)) AS ar2
                 FROM   ProductionTest
            ) x
            pivot 
            (
                MAX(ar2)
                for stepId in (' + @cols + ')
            ) p '

execute (@query)

查询仍然很复杂,但会在查询运行时创建列。

这是SQL Fiddle with a Demo

【讨论】:

以上是关于使用 PIVOT/UNPIVOT 将行转换为列的主要内容,如果未能解决你的问题,请参考以下文章

在 Sql Server 中使用 Pivot/unpivot 将单行转换为单列

将行转换为列

使用R将行转换为列,将列转换为行

使用枢轴将行转换为列

SQL Server中行列转换 Pivot UnPivot

将矩阵转换为 3 列表('reverse pivot'、'unpivot'、'flatten'、'normalize')