反透视具有多列的数据 - 请语法帮助

Posted

技术标签:

【中文标题】反透视具有多列的数据 - 请语法帮助【英文标题】:Unpivot Data with Multiple Columns - Syntax Help Please 【发布时间】:2014-07-18 04:21:40 【问题描述】:

我有以下数据要取消透视

我创建了这个查询来取消透视“实际”行,但似乎无法弄清楚取消透视“Plan”和“PriorYear”的语法。

SELECT FiscalYear, Period, MetricName, ActualValue
FROM vw_ExecSummary
UNPIVOT
(ActualValue FOR MetricName IN ( [Net Revenue], [Total C.S. Salaries]
)) AS unpvt  
WHERE [Type] = 'Actual'

未透视的数据看起来像这样,但我还想在下方 ActualValue 列的右侧添加 Plan 和 PriorYear 列

任何帮助将不胜感激。谢谢。

【问题讨论】:

【参考方案1】:

我目前无法对此进行测试,但我认为它是这样工作的。首先,你需要UNPIVOT所有数据:

SELECT fiscalYear, period, type, metricName, metricValue
FROM vw_ExecSummary
UNPIVOT (metricValue FOR metricName IN ([Net Revenue], [Total C.S. Salaries])) unpvt

这应该会导致一个看起来像这样的表格:

fiscalYear  period  type      metricName             metricValue
===================================================================
15          1       'Actual'  'Net Revenue'          3676798.98999997
15          1       'Actual'  'Total C.S. Salaries'  1463044.72
15          1       'Plan'    'Net Revenue'          3503920.077405
...................... (remaining rows omitted)

然后我们可以像往常一样PIVOT 行来获取新列(这就是它的用途):

SELECT fiscalYear, period, metricName, 
       [Actual] AS actualValue, [Plan] AS planValue, [PriorYear] AS priorYearValue
FROM <previous_data>
PIVOT (SUM(metricValue) FOR (type IN ([Actual], [Plan], [PriorYear]) pvt

SUM(...) 实际上不应该在这里做任何事情,因为推测其他列包含一个唯一的行,但我们需要使用聚合函数)

...应该会产生类似于以下内容的内容:

fiscalYear  period  metricName     actualValue       planValue       priorYearValue
======================================================================================
15          1       'Net Revenue'  3676798.98999997  3503920.077405  40436344.4499999
...................................... (remaining rows omitted)

所以把它放在一起看起来像这样:

SELECT fiscalYear, period, metricName, 
       [Actual] AS actualValue, [Plan] AS planValue, [PriorYear] AS priorYearValue
FROM (SELECT fiscalYear, period, type, metricName, metricValue
      FROM vw_ExecSummary
      UNPIVOT (metricValue FOR metricName IN ([Net Revenue], [Total C.S. Salaries])) unpvt) unpvt
PIVOT (SUM(metricValue) FOR type IN ([Actual], [Plan], [PriorYear])) AS pvt

SQL Fiddle Example


不过,我只有一个担心:3676798.989999973503920.077405 等值让我认为这些列是浮点(即REALFLOAT),但这些值是以货币用途命名的。如果是这种情况......您知道浮点值不能完全存储像.1 这样的东西,对(即,您实际上不能为值添加一角钱) ?而且,当值变得足够大时,您也不能再添加1 了吗?通常在处理货币值时,您应该使用基于定点类型的东西,例如 DECIMALNUMERIC

【讨论】:

感谢您的解决方案 - 准确!我确实注意到 PIVOT 语句中“类型”一词之前的括号不正确。我删除了它,并在 PIVOT 语句的末尾添加了一个右括号。像魅力一样工作! @Jason - 啊,谢谢。 #更正#。这就是为什么我喜欢先测试它们。那么这两个money列的的类型是什么? 我相信类型是浮动的(目前不在我的工作笔记本电脑前)。 @Jason - 啊,好吧,向会计解释他们多余的钱从哪里来/从哪里来的很有趣。【参考方案2】:

这是Itzig Ben-Gan's cross apply values pivoting的情况:

create table #data (FiscalYear smallint, Period tinyint, ValueType nvarchar(25), NetRevenue float, Salaries float);
insert into #data values 
    (15,1,N'Actual',3676798.98999,1463044.71999),
    (15,1,N'Plan',3503920.977405,1335397.32878),
    (15,1,N'PriorYear',4043634.449,1543866.89);

select  d.FiscalYear, d.Period,
        ActualNetRevenue = sum(v.ActualNetRevenue), ActualSalaries = sum(v.ActualSalaries),
        PlanNetRevenue = sum(v.PlanNetRevenue), PlanSalaries = sum(v.PlanSalaries),
        PriorYearNetRevenue = sum(v.PriorYearNetRevenue), PriorYearSalaries = sum(v.PriorYearSalaries)
from    #data d
cross apply
        (values
        (N'Actual',d.NetRevenue,d.Salaries,0,0,0,0),
        (N'Plan',0,0,d.NetRevenue,d.Salaries,0,0),
        (N'PriorYear',0,0,0,0,d.NetRevenue,d.Salaries))
        v (ValueType, ActualNetRevenue, ActualSalaries, PlanNetRevenue, PlanSalaries, PriorYearNetRevenue, PriorYearSalaries)
where   d.ValueType = v.ValueType
group by d.FiscalYear, d.Period;

drop table #data;

【讨论】:

谢谢,但此示例将所有项目放在一行中。上面的解决方案是我打算做的。

以上是关于反透视具有多列的数据 - 请语法帮助的主要内容,如果未能解决你的问题,请参考以下文章

将行值反透视到多列

将多列反透视成行

SQL查询对多列进行反透视和联合

具有多列聚合的 SQL Server 数据透视表

具有多列日期的 SQL Server 数据透视表

透视数据并将单列放入具有关联行的多列中