使用UNPIVOT将列转置为行

时间:2012-09-24 16:05:48

标签: sql-server sql-server-2008 tsql

我有一张表,由于某种原因,它有像这样的硬编码值:

Row ID    QtyC1   QtyC2  QtyC3   QtyC4  QtyN1   QtyN2  QtyN3   QtyN4  
100       10      5      8       9      11      12     5       6
101       9       11     12      5      6       10     4       9

该表有35列和大约12k条记录(意味着约500k值),并且不断添加和修改。

我试图将其转换为:

Row ID  Year  Period  Val
100     C     1       10
100     C     2       5
100     C     3       8
100     C     4       9
100     N     1       11
100     N     2       12
100     N     3       5
100     N     4       6

到目前为止,我已设法使用此查询将其拆分为单个值:

SELECT Row ID, YP, Val

FROM (SELECT Row ID
    , QtyC1 AS C1
    , QtyC2 AS C2
    , QtyC3 AS C3
    , QtyC4 AS C4
    , QtyN1 AS N1
    , QtyN2 AS N2
    , QtyN3 AS N3
    , QtyN4 AS N4

FROM MyTable
) SUB
UNPIVOT (Val FOR YP IN (C1,C2,C3,C4,N1,N2,N3,N4)) AS PVT

这为我提供了一个识别值(例如C1)但是如何拆分它以便我有一个数字句点和一年中的单个字符(1C )?

我可以看到将字符串分成两部分是可能的,但我希望尽可能采用更清洁的方式。

2 个答案:

答案 0 :(得分:2)

您可以使用YPLEFT()RIGHT()等轻松拆分SUBSTRING()字符串。我的建议是如何处理您的UNPIVOT。看起来你有很多列UNPIVOT所以我的建议可能是实现动态SQL来执行这个查询。你会这样做的:

declare @colsUnpivot varchar(max),
  @query  AS NVARCHAR(MAX),
  @cols  varchar(max)

select @colsUnpivot = stuff((select ','
                             +quotename(replace(C.name, 'Qty', ''))
         from sys.columns as C
         where C.object_id = object_id('yourtable') and
               C.name like 'Qty%'
         for xml path('')), 1, 1, '')

select @cols = stuff((select ','
                      +quotename(C.name) + ' as ' + replace(C.name, 'Qty', '')
         from sys.columns as C
         where C.object_id = object_id('yourtable') and
               C.name like 'Qty%'
         for xml path('')), 1, 1, '')

set @query 
  = 'select rowid, 
          left(YP, 1) YP,
          cast(right(YP, len(YP) - 1) as int) period,
          Val
     from
     (
        select rowid, ' + @cols + '
        from yourtable
     ) x1
     unpivot
     (
        val for YP IN (' + @colsUnpivot + ')
     ) u'

exec(@query)

请参阅SQL Fiddle with Demo

答案 1 :(得分:1)

为什么这看起来不干净?

SELECT Row ID, left(YP, 1) as year, cast(right(yp, 1) as int) as period, Val
FROM (SELECT Row ID
    , QtyC1 AS C1
    , QtyC2 AS C2
    , QtyC3 AS C3
    , QtyC4 AS C4
    , QtyN1 AS N1
    , QtyN2 AS N2
    , QtyN3 AS N3
    , QtyN4 AS N4
FROM MyTable
) SUB
UNPIVOT (Val FOR YP IN (C1,C2,C3,C4,N1,N2,N3,N4)) AS PVT