sql - 使用 SQL 将行转换为列

标签 sql sql-server sql-server-2008 t-sql

我正在尝试解决问题。我想将行更改为列,但我不确定如何执行此操作。 Pivot 是一个解决方案,但没有按照我想要的方式获取列。这是一个例子。

The raw data

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

The resultset

基本上,对于相同的请求 ID,季度需要按年份分布在同一行上。我曾尝试过CASE,但这对于这样的事情来说似乎有点过分了。

这是一个fiddle首先。

谢谢。

最佳答案

要获得完全弹性的解决方案,您应该搜索动态枢轴。如果您提前几年知道,您可以使用:

;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

动态枢轴(您不需要提前几年知道):

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

关于sql - 使用 SQL 将行转换为列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35220846/

相关文章:

java - 如果Oracle中不存在则创建一个表(使用Java)

c# - 以编程方式将列添加到 SQL Server 数据库

c# - 一个 datagridview 和来自两个数据库和 USB 的数据。如何开始?

sql-server - 在 SUM 字段上使用 HAVING 或 WHERE

mysql - 获取列等于字符串的最后一个 ID

sql在连接内连接?

C# 方法中使用的变量上的上下文错误

sql-server - 使用本地 SQL Server 和最佳实践的 Azure 搜索数据源?

sql - 远程 MSSQL/ODBC 与 Rails 同步

sql-server - 如何在 SQL Server 2008 中实现自治事务?