【问题标题】:SSMS Rolling Average over Day of Week一周中某一天的 SSMS 滚动平均值
【发布时间】:2019-04-08 18:27:33
【问题描述】:

领导层想了解队友在周一和周五与其他工作周相比的表现。以下是 Teammate X 在两个月期间的日常表现的示例 temp dbo。每个后续的队友都有不同的起点,从那里开始测量。我最初考虑将 UNBOUNDED PRECEDING 与各种开始日期结合使用,但 windows 功能不合作。救命!

CREATE TABLE #RollingAverage
(
    [Date]     DATE PRIMARY KEY
    ,[Value]   INT
);

INSERT INTO #RollingAverage
SELECT '2019-01-02',626
UNION ALL SELECT '2019-01-03',231 UNION ALL SELECT '2019-01-04',572
UNION ALL SELECT '2019-01-07',775 UNION ALL SELECT '2019-01-09',660
UNION ALL SELECT '2019-01-10',662 UNION ALL SELECT '2019-01-11',541
UNION ALL SELECT '2019-01-14',849 UNION ALL SELECT '2019-01-15',632
UNION ALL SELECT '2019-01-16',906 UNION ALL SELECT '2019-01-18',961
UNION ALL SELECT '2019-01-21',501 UNION ALL SELECT '2019-01-24',311
UNION ALL SELECT '2019-01-25',614 UNION ALL SELECT '2019-01-28',296
UNION ALL SELECT '2019-01-29',390 UNION ALL SELECT '2019-01-31',804
UNION ALL SELECT '2019-02-01',928 UNION ALL SELECT '2019-02-05',855
UNION ALL SELECT '2019-02-06',605 UNION ALL SELECT '2019-02-08',283
UNION ALL SELECT '2019-02-12',144 UNION ALL SELECT '2019-02-14',382
UNION ALL SELECT '2019-02-15',862 UNION ALL SELECT '2019-02-18',549
UNION ALL SELECT '2019-02-19',401 UNION ALL SELECT '2019-02-20',515
UNION ALL SELECT '2019-02-21',590 UNION ALL SELECT '2019-02-22',625
UNION ALL SELECT '2019-02-25',304 UNION ALL SELECT '2019-02-26',402
UNION ALL SELECT '2019-02-27',326;

AVG(Value) over (ORDER BY [Date] ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) 不起作用

【问题讨论】:

  • 定义“无效”。如果出现错误,错误消息是什么?如果你得到了结果,它们有什么问题?
  • 我得到的错误是“'ROWS'附近的语法不正确”

标签: sql-server ssms


【解决方案1】:

您需要了解的第一件事是,您的“日常”表现并非每天。一个简单的解决方案是填补空白,以便能够有效地计算天数。

我使用动态生成日历表的 CTE 填补了空白,但如果可用,您可以使用永久日历表。

WITH 
E(n) AS(
    SELECT n FROM (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0))E(n)
),
E2(n) AS(
    SELECT a.n FROM E a, E b
),
cteCalendar(calDate) AS(
    SELECT TOP (61) 
        CAST( DATEADD( DD, 1-ROW_NUMBER() OVER(ORDER BY (SELECT NULL)), GETDATE()) AS date) AS calDate
    FROM E2
),
cteRollingAverages AS(        
    SELECT ra.[Date], 
        ra.value,
        AVG(Value) over (ORDER BY calDate ROWS BETWEEN 7 PRECEDING AND CURRENT ROW) RollingAverage
    FROM #RollingAverage AS ra
    RIGHT JOIN cteCalendar AS c ON ra.[Date] = c.calDate
)
SELECT *
FROM cteRollingAverages
WHERE [Date] IS NOT NULL
ORDER BY [Date];

另一种选择是使用 APPLY。这不受特定日期的限制。

SELECT *
FROM #RollingAverage r
CROSS APPLY( SELECT AVG(i.[Value]) AS RollingAvg
            FROM #RollingAverage i
            WHERE i.[Date] BETWEEN DATEADD( DD, -7, r.[Date]) AND r.[Date]) av
ORDER BY [Date];

【讨论】:

  • 我明白你在说什么。我不希望在计数中包含 NULL 或 0 值。样本集中缺失的日期表示缺勤天数。我只是想在活跃的日子里平均表现。
  • 查询不包括 NULL 或 0 值。聚合函数(包括窗口函数)省略了 NULL,我们不会添加零来包含它们。但是,您需要添加缺失的日期以保持行数一致。
  • 当我得到 6 个月的数据乘以额外的队友时,我是否将不得不填充所有那些空闲的日子。有没有更简单的方法来编译这个条件聚合?
  • 我添加了一个不同的选项,可能会更好地为您服务。我建议您比较两者的性能。
  • 谢谢,路易斯。我觉得术语将其与我的最终目标区分开来。我不是在寻找“移动平均线”(过去 X 天),而是有条件地从一个初始起点开始。
猜你喜欢
  • 2011-05-24
  • 2018-02-08
  • 2020-04-25
  • 2021-06-14
  • 2016-12-24
  • 1970-01-01
  • 1970-01-01
  • 2021-06-04
  • 1970-01-01
相关资源
最近更新 更多