运行 缺少日期的总和

Running sum with missing dates

我有一个 table 这样的数据:

PeriodYearMonth Reg      PartNo             ComponentRemovals   RunningRemovals
2019 10         G-NHVP   109-0740V01-137    1                    1
2019 11         G-NHVP   109-0740V01-137    1                    2  
2019 12         G-NHVP   109-0740V01-137    1                    3
2020 01         G-NHVP   109-0740V01-137    1                    4
2019 10         OO-NSF   11-13354P          1                    1
2019 09         G-NHVR   11-13354P          2                    2 
2019 10         OY-HMV   11-13354P          1                    1

在最后一列中,我计算了 7 个月 运行 每个 PartNo 和每个 Reg 的移除总和。为此,我编写了以下代码:

/****** Find Running Component Removals ******/
SELECT  [PeriodYearMonth]
      ,[Reg]
      ,[PartNo]
      ,[ComponentRemovals]
      ,sum(sum(ComponentRemovals)) over (Partition by [Reg], PartNo Order By PeriodYearMonth, PeriodYearMonth rows between 6 preceding and current row) as RunningRemovals
      ,[ConfirmedFailures]
      , sum(sum(ConfirmedFailures)) over (Partition by [Reg], PartNo Order By PeriodYearMonth, PeriodYearMonth rows between 6 preceding and current row) as RunningFailures

  FROM [RALNHVTST].[dbo].[vtRelRepComponentsRemovalsByPartNo]

  Group by Reg, PartNo, ComponentRemovals, ConfirmedFailures, PeriodYearMonth
  Order by PartNo

但是,由于并非所有月份都包含在 PeriodYearMonth 列中,因此结果不正确。我在网上看到了简单案例的解决方案,但对我来说棘手的部分是,我需要为每个 PartNo、每个 Reg 和每个月输入一个条目。

如有任何帮助,我们将不胜感激。

此致

In the last column I calculated the running sum of removals per PartNo and per Reg over the past 7 months.

删除窗口子句和过滤器:

select [PeriodYearMonth], [Reg], [PartNo], [ComponentRemovals],
        sum(sum(ComponentRemovals)) over (Partition by [Reg], PartNo Order By PeriodYearMonth, PeriodYearMonth) as RunningRemovals
        [ConfirmedFailures],
        sum(sum(ConfirmedFailures)) over (Partition by [Reg], PartNo Order By PeriodYearMonth, PeriodYearMont) as RunningFailures
from [RALNHVTST].[dbo].[vtRelRepComponentsRemovalsByPartNo]
where PeriodYearMonth >= format(dateadd(month, -7, getdate()), 'yyyy MM')
group by Reg, PartNo, ComponentRemovals, ConfirmedFailures, PeriodYearMonth
Order by PartNo

要解决此问题,您需要为所有 PeriodYearMonth 值(使用递归 CTE 生成)以及不同的 Reg 和 [=15= 创建单独的派生 table ] 对,然后 CROSS JOIN 它们相互组合以获得列的所有组合。然后可以将此组合 table LEFT JOIN 编辑为原始 table 以获得每个 RegPartNoPeriodYearMonthComponentRemovals ],然后可以使用 window 函数对这些求和:

WITH CTE AS (
  SELECT CONVERT(DATE, CONCAT(REPLACE(MIN(PeriodYearMonth), ' ', '-'), '-01'), 23)  AS date, 
         CONVERT(DATE, CONCAT(REPLACE(MAX(PeriodYearMonth), ' ', '-'), '-01'), 23)  AS max_date
  FROM vtRelRepComponentsRemovalsByPartNo
  UNION ALL
  SELECT DATEADD(MONTH, 1, date), max_date
  FROM CTE
  WHERE date < max_date
)
SELECT FORMAT(CTE.date, 'yyyy MM') AS PeriodYearMonth
     , rp.Reg
     , rp.PartNo
     , COALESCE(v.ComponentRemovals, 0) AS ComponentRemovals
     , SUM(COALESCE(v.ComponentRemovals, 0)) OVER (PARTITION BY rp.Reg, rp.PartNo ORDER BY FORMAT(CTE.date, 'yyyy MM')
                                                   ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS RunningRemovals
FROM CTE
CROSS JOIN (SELECT DISTINCT Reg, PartNo FROM vtRelRepComponentsRemovalsByPartNo) rp
LEFT JOIN vtRelRepComponentsRemovalsByPartNo v
       ON v.PeriodYearMonth = FORMAT(CTE.date, 'yyyy MM')
      AND v.Reg = rp.Reg
      AND v.PartNo = rp.PartNo
ORDER BY rp.Reg, rp.PartNo, CTE.date

输出

PeriodYearMonth     Reg     PartNo              ComponentRemovals   RunningRemovals
2019 09             G-NHVP  109-0740V01-137     0                   0
2019 10             G-NHVP  109-0740V01-137     1                   1
2019 11             G-NHVP  109-0740V01-137     1                   2
2019 12             G-NHVP  109-0740V01-137     1                   3
2020 01             G-NHVP  109-0740V01-137     1                   4
2019 09             G-NHVR  11-13354P           2                   2
2019 10             G-NHVR  11-13354P           0                   2
2019 11             G-NHVR  11-13354P           0                   2
2019 12             G-NHVR  11-13354P           0                   2
2020 01             G-NHVR  11-13354P           0                   2
2019 09             OO-NSF  11-13354P           0                   0
2019 10             OO-NSF  11-13354P           1                   1
2019 11             OO-NSF  11-13354P           0                   1
2019 12             OO-NSF  11-13354P           0                   1
2020 01             OO-NSF  11-13354P           0                   1
2019 09             OY-HMV  11-13354P           0                   0
2019 10             OY-HMV  11-13354P           1                   1
2019 11             OY-HMV  11-13354P           0                   1
2019 12             OY-HMV  11-13354P           0                   1
2020 01             OY-HMV  11-13354P           0                   1

Demo on SQLFiddle

请注意,如果 all PeriodYearMonth 感兴趣的值出现在 vtRelRepComponentsRemovalsByPartNo 中,您可以简单地使用 SELECT DISTINCT ... 子查询来获取这些值而不是递归 CTE 例如

SELECT d.PeriodYearMonth
     , rp.Reg
     , rp.PartNo
     , COALESCE(v.ComponentRemovals, 0) AS ComponentRemovals
     , SUM(COALESCE(v.ComponentRemovals, 0)) OVER (PARTITION BY rp.Reg, rp.PartNo ORDER BY d.PeriodYearMonth
                                                   ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS RunningRemovals
FROM (SELECT DISTINCT PeriodYearMonth FROM vtRelRepComponentsRemovalsByPartNo) d
CROSS JOIN (SELECT DISTINCT Reg, PartNo FROM vtRelRepComponentsRemovalsByPartNo) rp
LEFT JOIN vtRelRepComponentsRemovalsByPartNo v
       ON v.PeriodYearMonth = d.PeriodYearMonth
      AND v.Reg = rp.Reg
      AND v.PartNo = rp.PartNo
ORDER BY rp.Reg, rp.PartNo, d.PeriodYearMonth

Demo on SQLFiddle