【问题标题】:SQL 2012 - Pivot and UnpivotSQL 2012 - 透视和反透视
【发布时间】:2016-06-29 02:18:02
【问题描述】:

我已将数据汇总在一个类似于此的表格中:

Customer Year Month No_trans spend  points
1        2015 1     30       400    10
1        2015 2     20       150    5
1        2015 3     10       500    15
2        2015 1     5        100    7

我想尝试使用 Pivot/Unpivot 来改变这个,可以吗?

??????   Customer 2015_1 2015_2 2015_3  
No_trans 1        30     20     10               
Spend    1        400    150    500
Points   1        10     5      15
No_trans 2        5      0      0               
Spend    2        100    0      0
Points   2        7      0      0

谢谢

【问题讨论】:

  • 您能否进一步说明您想要的结果?
  • 2 2015 1 5 100 7 您应该在2015_1 列中具有所需结果而不是2015_3 的值

标签: sql sql-server tsql sql-server-2012 pivot


【解决方案1】:

您可以使用动态 SQL 转置表:

DECLARE @cols NVARCHAR(MAX) = 
                STUFF((SELECT DISTINCT ',' + QUOTENAME(CONCAT([Year], '_', [Month]))
                      FROM #tab
                      FOR XML PATH(''), TYPE
                     ).value('.', 'NVARCHAR(MAX)') 
                     , 1, 1, '');

DECLARE @query NVARCHAR(MAX) = 
FORMATMESSAGE(
N'SELECT col_name, customer, %s
FROM (SELECT [year_month] = CONCAT([Year], ''_'', [Month]),
             Customer, No_Trans, spend, points
      FROM #tab) AS sub
UNPIVOT
(
    val FOR col_name  IN (No_trans, spend, points)
) AS unpvt
PIVOT
(
    MAX(val) FOR [year_month] IN (%s)
) AS pvt
ORDER BY customer, col_name;', @cols, @cols); 

EXEC [dbo].[sp_executesql] @query;

LiveDemo

输出:

╔══════════╦══════════╦════════╦════════╦════════╗
║   col    ║ customer ║ 2015_1 ║ 2015_2 ║ 2015_3 ║
╠══════════╬══════════╬════════╬════════╬════════╣
║ No_Trans ║        1 ║     30 ║     20 ║     10 ║
║ points   ║        1 ║     10 ║      5 ║     15 ║
║ spend    ║        1 ║    400 ║    150 ║    500 ║
║ No_Trans ║        2 ║      5 ║        ║        ║
║ points   ║        2 ║      7 ║        ║        ║
║ spend    ║        2 ║    100 ║        ║        ║
╚══════════╩══════════╩════════╩════════╩════════╝

如果你想让zeros 出现在缺失的位置,你可以使用ISNULL/COALESCE。请注意,并非所有数据类型都可以替换为 0 (int)

LiveDemo2

编辑:

FORMATMESSAGE 是用字符串替换%s 的好方法。可以通过简单的REPLACE轻松更改:

 DECLARE @query NVARCHAR(MAX) = 
 N'SELECT col1, col2, <placeholder>
   FROM ...
   ...
   PIVOT( MAX(col) IN col2 IN (<placeholder>)
   ...';

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

 -- for debug
 PRINT @query;

它是如何工作的:

  1. 在子查询中生成[year_month]
  2. UNPIVOT 数据(列到行)
  3. PIVOT 结果(行到列)
  4. 用动态 SQL 包装它以允许在事先不知道 [year_month] 的情况下生成列。

【讨论】:

  • 您好,感谢您的帮助,我想按特定行订购 col,我如何按客户合并订单,case col 当 'No_trans' 然后 1,当 'Spend' 然后 2,当'points' 然后 3 else 4 end..
  • 嗨,lad2025,我是动态 sql 的新手,尤其是数据透视,你能通过代码简单地解释每个部分的含义或正在做什么吗?例如。 SELECT col_name, customer, %s, "%s" 是做什么的?或者有什么在线的地方可以指导我阅读?
  • 我对@9​​87654339@ 的投票。从来不知道这样的功能存在;)
  • @MotoGP 我喜欢它,因为它类似于 printf in C :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-09
  • 2011-05-23
相关资源
最近更新 更多