使用SQL将行转换为列

时间:2016-02-05 09:44:45

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

我正在努力解决问题。我想将行更改为列,但我不知道如何执行此操作。 Pivot是一个解决方案,但是没有按照我的要求提取列。这是一个例子。

The raw data

上面的表格是我想要使用的表格,并将其转换为类似下面的表格

The resultset

基本上,对于相同的请求ID,需要在同一行上分配多年。我曾尝试过 CASE ,但对于类似的事情来说,这似乎有些过分。

这是一个fiddle开头。

感谢。

2 个答案:

答案 0 :(得分:2)

要获得完全弹性的解决方案,您应该搜索动态数据透视。如果您事先了解多年,可以使用:

;WITH cte AS
(
   SELECT ReqId,quater1,quater2,quater3,quater4
        ,[q1] = CONCAT('Q1_',[year])
        ,[q2] = CONCAT('Q2_',[year])
        ,[q3] = CONCAT('Q3_',[year])
        ,[q4] = CONCAT('Q4_',[year])
   FROM #forecast
)
SELECT ReqId
    ,[Q1_2014] = MAX([Q1_2014])
    ,[Q2_2014] = MAX([Q2_2014])
    ,[Q3_2014] = MAX([Q3_2014])
    ,[Q4_2014] = MAX([Q4_2014])
    ,[Q1_2015] = MAX([Q1_2015])
    ,[Q2_2015] = MAX([Q2_2015])
    ,[Q3_2015] = MAX([Q3_2015])
    ,[Q4_2015] = MAX([Q4_2015])
    ,[Q1_2016] = MAX([Q1_2016])
    ,[Q2_2016] = MAX([Q2_2016])
    ,[Q3_2016] = MAX([Q3_2016])
    ,[Q4_2016] = MAX([Q4_2016])
    ,[Q1_2017] = MAX([Q1_2017])
    ,[Q2_2017] = MAX([Q2_2017])
    ,[Q3_2017] = MAX([Q3_2017])
    ,[Q4_2017] = MAX([Q4_2017])  
FROM cte
PIVOT (MAX(quater1) FOR [q1] IN ([Q1_2014],[Q1_2015],[Q1_2016],[Q1_2017])) AS pvt1
PIVOT (MAX(quater2) FOR [q2] IN ([Q2_2014],[Q2_2015],[Q2_2016],[Q2_2017])) AS pvt2
PIVOT (MAX(quater3) FOR [q3] IN ([Q3_2014],[Q3_2015],[Q3_2016],[Q3_2017])) AS pvt3
PIVOT (MAX(quater4) FOR [q4] IN ([Q4_2014],[Q4_2015],[Q4_2016],[Q4_2017])) AS pvt4
GROUP BY ReqId

LiveDemo

输出:

╔════════╦══════════╦══════════╦══════════╦══════════╦══════════╦══════════╦══════════╦══════════╦══════════╦══════════╦══════════╦══════════╦══════════╦══════════╦══════════╦═════════╗
║ ReqId  ║ Q1_2014  ║ Q2_2014  ║ Q3_2014  ║ Q4_2014  ║ Q1_2015  ║ Q2_2015  ║ Q3_2015  ║ Q4_2015  ║ Q1_2016  ║ Q2_2016  ║ Q3_2016  ║ Q4_2016  ║ Q1_2017  ║ Q2_2017  ║ Q3_2017  ║ Q4_2017 ║
╠════════╬══════════╬══════════╬══════════╬══════════╬══════════╬══════════╬══════════╬══════════╬══════════╬══════════╬══════════╬══════════╬══════════╬══════════╬══════════╬═════════╣
║     1  ║      10  ║      20  ║      30  ║      40  ║      50  ║      60  ║      70  ║      80  ║      90  ║     100  ║     110  ║     120  ║ (null)   ║ (null)   ║ (null)   ║ (null)  ║
║     2  ║      10  ║      20  ║      30  ║      40  ║      50  ║      60  ║      70  ║      80  ║      90  ║     100  ║     110  ║     120  ║ 130      ║ 140      ║ 150      ║ 160     ║
╚════════╩══════════╩══════════╩══════════╩══════════╩══════════╩══════════╩══════════╩══════════╩══════════╩══════════╩══════════╩══════════╩══════════╩══════════╩══════════╩═════════╝

附录1

可替换地:

;WITH cte AS (
  SELECT ReqId, [q] ='Q1_' + CAST([year] AS CHAR(4)), quater = quater1  FROM #forecast
  UNION ALL SELECT ReqId, [q] ='Q2_' + CAST([year] AS CHAR(4)), quater2 FROM #forecast
  UNION ALL SELECT ReqId, [q] ='Q3_' + CAST([year] AS CHAR(4)), quater3 FROM #forecast
  UNION ALL SELECT ReqId, [q] ='Q4_' + CAST([year] AS CHAR(4)), quater4 FROM #forecast
)
SELECT *
FROM cte
PIVOT (MAX(quater) FOR q IN (Q1_2014,Q2_2014,Q3_2014,Q4_2014,
                             Q1_2015,Q2_2015,Q3_2015,Q4_2015,
                             Q1_2016,Q2_2016,Q3_2016,Q4_2016,
                             Q1_2017,Q2_2017,Q3_2017,Q4_2017)
) AS pvt;

LiveDemo2

附录2

Dynamic Pivot(您不需要提前知道几年):

DECLARE @sql NVARCHAR(MAX) = N'
WITH cte AS (
  SELECT ReqId,[q] =''Q1_'' + CAST([year] AS CHAR(4)),quater = quater1  FROM #forecast
  UNION ALL SELECT ReqId,[q] =''Q2_'' + CAST([year] AS CHAR(4)),quater2 FROM #forecast
  UNION ALL SELECT ReqId,[q] =''Q3_'' + CAST([year] AS CHAR(4)),quater3 FROM #forecast
  UNION ALL SELECT ReqId,[q] =''Q4_'' + CAST([year] AS CHAR(4)),quater4 FROM #forecast
)
SELECT *
FROM cte
PIVOT (MAX(quater) FOR q IN (<placeholder>)
) AS pvt;';

DECLARE @cols NVARCHAR(MAX) = 
                STUFF((SELECT ',' + QUOTENAME('Q1_' + CAST([year] AS CHAR(4))) +
                              ',' + QUOTENAME('Q2_' + CAST([year] AS CHAR(4))) +
                              ',' + QUOTENAME('Q3_' + CAST([year] AS CHAR(4))) +
                              ',' + QUOTENAME('Q4_' + CAST([year] AS CHAR(4)))
                      FROM (SELECT DISTINCT [year] FROM #forecast) cte
                      ORDER BY [year]
                      FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') , 1, 1, '');

SET @sql = REPLACE(@sql, '<placeholder>', @cols);

EXEC [dbo].[sp_executesql] @sql;

LiveDemo3

答案 1 :(得分:0)

看那个:

Concatenate Rows

也许给你一个方法。