MS SQL PIVOT MONTH, QUARTER AND YEAR - 如果存在类似月份值,则显示错误数据的季度

Posted

技术标签:

【中文标题】MS SQL PIVOT MONTH, QUARTER AND YEAR - 如果存在类似月份值,则显示错误数据的季度【英文标题】:MS SQL PIVOT MONTH, QUARTER AND YEAR- The QUARTER Showing Wrong Data for If Similar Month Values Present 【发布时间】:2021-08-18 14:14:55 【问题描述】:

我在表中有以下数据结构。

UNITDATE    UNIT
2020-01-01  550.00
2020-01-01  777.00
2020-02-01  887.00
2020-02-01  111.00
2020-03-01  501.00
2020-03-01  500.00
2020-04-01  516.00
2020-05-01  516.00
2020-06-01  723.00

但由于 2020-04-01 和 2020-05-01 具有相同的值,因此以下数据透视查询返回了错误的季度 SUM(Q2) 结果。

SELECT SUM([1]) AS Jan, SUM([2]) AS Feb, SUM([3]) AS Mar,SUM(Q1) AS Q1,  
                SUM([4]) AS Apr, SUM([5]) AS May, SUM([6]) AS Jun, SUM(Q2) AS Q2, 
                SUM([7]) AS Jul, SUM([8]) AS Aug, SUM([9]) AS Sep, SUM(Q3) AS Q3,
                SUM([10]) AS Oct, SUM([11]) AS Nov, SUM([12]) AS Dec, SUM(Q4) AS Q4, SUM([2020]) AS YEARLY 
        FROM (SELECT  
        DATEPART(MONTH, UNITDATE) as month,
        CAST('Q' + CAST(DATEPART(QUARTER, UNITDATE) AS VARCHAR(1)) AS VARCHAR(2)) AS quarter,
        DATEPART(YEAR, UNITDATE) as year,
        SUM(UNIT) AS M,
        SUM(UNIT) AS Q,
        SUM(UNIT) AS Y FROM MyTable WHERE DATEPART(YEAR, UNITDATE) = 2020 GROUP BY UNITDATE) as yearData 
        PIVOT (SUM(M) FOR month IN ( [1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12])) AS PM     
        PIVOT (SUM(Q) FOR quarter IN ([Q1],[Q2],[Q3],[Q4])) AS PQ
        PIVOT (SUM(Y) FOR year IN ([2020])) AS PY;

Jan Feb Mar Q1  Apr May Jun Q2  Jul Aug Sep Q3  Oct Nov Dec Q4  YEARLY
1327.00 998.00  1001.00 3326.00 516.00  516.00  723.00  1239.00 NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    4565.00

有人遇到过类似的问题吗,请指教。

【问题讨论】:

【参考方案1】:

不要使用PIVOT 运算符,它具有限制性且笨重。条件聚合会更容易:

WITH YourData AS(
    SELECT *
    FROM(VALUES(CONVERT(date,'2020-01-01'),550.00),
               (CONVERT(date,'2020-01-01'),777.00),
               (CONVERT(date,'2020-02-01'),887.00),
               (CONVERT(date,'2020-02-01'),111.00),
               (CONVERT(date,'2020-03-01'),501.00),
               (CONVERT(date,'2020-03-01'),500.00),
               (CONVERT(date,'2020-04-01'),516.00),
               (CONVERT(date,'2020-05-01'),516.00),
               (CONVERT(date,'2020-06-01'),723.00))V(UNITDATE,UNIT))
SELECT SUM(CASE DATEPART(MONTH,UNITDATE) WHEN 1 THEN UNIT END) AS Jan,
       SUM(CASE DATEPART(MONTH,UNITDATE) WHEN 2 THEN UNIT END) AS Feb,
       SUM(CASE DATEPART(MONTH,UNITDATE) WHEN 3 THEN UNIT END) AS Mar,
       SUM(CASE WHEN DATEPART(MONTH,UNITDATE) BETWEEN 1 AND 3 THEN UNIT END) AS Q1,
       SUM(CASE DATEPART(MONTH,UNITDATE) WHEN 4 THEN UNIT END) AS Apr,
       -- You get the idea
       SUM(UNIT) AS Yearly
FROM YourData
WHERE UNITDATE >= '20200101'
  AND UNITDATE < '20210101';

【讨论】:

谢谢,但是在性能方面,pivot 更适合大型数据集,对吧?我在上面的帖子中分享了一部分数据。 为什么你认为PIVOT 会“更快”? 不确定,我没有比较这些,但假设它的 CTE 支点会做得更好。对吗? CTE 只是一个表达式。写得不好的表达式会阻碍性能,但这不是问题所在。如果您在UNITDATE 上有一个索引,则该查询INCLUDEs UNIT 可能会非常快。如果您说PIVOT 更快,则需要使用查询计划来证明这一点。 谢谢你,我也是 SQL 查询的新手——我没有得到你的答案“查询,只要你在 UNITDATE 上有一个包含 UNIT 的索引可能会很快”有什么办法吗用我当前的数据集实现这一目标

以上是关于MS SQL PIVOT MONTH, QUARTER AND YEAR - 如果存在类似月份值,则显示错误数据的季度的主要内容,如果未能解决你的问题,请参考以下文章

ms sql pivot 不起作用

在 MS SQL Server 2008 的 Pivot 中计算水平总计

MS SQL Pivot 来自多列的长数据

在 ms sql 中旋转 2 列并依次显示数据

SQL PIVOT 可以做这样的转换吗?

带有 IN CLAUSE 动态值的 SQL Pivot