我有一个SQL Server查询,它获取44家商店市场链的销售数据,它包括每个商店的 4 个值(销售额、销货成本、GP 和 GP 保证金),我声明了一个CTE并为每个商店加入了44 次以获得每个商店的4 个值作为列,如下所示:
查询:查询1
但是当我尝试将PIVOT
函数与动态 SQL 一起使用时,它会返回多个空值,如下所示:
查询:查询2
表##tbl1
包括我想要透视的数据集:
我使用了以下查询:(三个点代表要旋转的其余列)
select * from ##tbl1
pivot (sum(total_sales) for s in ([50001 Sales],[50002 Sales],...)) as pv_tb
pivot (sum(Margin) for m in ([50001 margin],[50002 margin],...)) as pv_tb1
pivot (sum(total_profit) for p in ([50001 profit],[50002 profit],...)) as pv_tb2
pivot (sum(total_cost) for c in ([50001 cost],[50002 cost],...)) as pv_tb3
我还使用动态 SQL 来传递里面的列名,PIVOT()
而不必单独编写每个列名,但为了排除故障,我只是向您展示了查询的样子。
我无法绕过使用这个132CROSS APPLY
列的结果,很难维护。UNPIVOT
谁能帮我找到比这更简单的方法?
结果是
这是我对这个问题的动态解决方案。我认为您在使用 pivot 语句时遇到的问题是,当您进行数据透视时,所有列都存在,这会给您带来那些错误的 NULL。即使它们不在选择列表中,透视运算符也会按它们分组(请参阅我如何在透视部分中进行子选择)。
至于性能,在底层,性能差异可以忽略不计,PIVOT 和 UNPIVOT 是看似丑陋/复杂的 SQL 的语法糖。我确实更喜欢使用它们,因为我认为它使代码更易于阅读且噪音更小。
在任何情况下,此解决方案都会提供所需的结果并动态执行。我唯一需要改变的是数据类型。UNPIVOT 运算符要求所有数据类型都是相同的,所以我只是强制它们为 NUMERIC(38,6),您可能需要添加转换步骤/CTE。
需要注意的一件事是它不对源表进行任何过滤。如果您需要添加过滤,那么您将需要在多个位置更新它,否则查询将开始为您提供带有 NULL 值的结果。在这种情况下,最好将您想要的结果转储到临时表中。
最后:这确实是最适合显示层做的工作。我不确定结果的去向,但是 SSRS 和 Excel 都内置了出色的数据透视操作,并且它们在动态处理这方面会比在 SQL 中做得更好。不过,我的解决方案: