计算具有重叠周期的值
Calculating values with overlapping periods
我有一个查询可以为 driver 的评估生成月度报告。一些 driver 可能几个月都没有报告。报告包含各种违规行为,其中一种违规行为是每月累计违规行为,并且每年 重新设置,这是在单独的查询 中完成的。一切工作都很好,除非客户向这部分添加了新要求。要求是将其从每年重置更改为重置一年中超过 180 天的任何违规行为。
这是一份报告的样本(一份 driver 报告):
RN ReportId DriverId StartDate EndDate Level1Vio Lv1YTD
-------------------- -------------------- -------------------- ----------------------- ----------------------- ----------- -----------
1 64 2073 2020-10-21 00:00:00.000 2020-11-21 23:59:59.000 1 1
2 65 2073 2020-11-24 05:13:04.133 2020-12-24 05:13:04.133 0 1
3 67 2073 2020-12-23 06:53:52.870 2021-01-23 06:53:52.870 0 1
4 68 2073 2021-01-22 06:33:43.127 2021-02-22 06:33:43.127 0 1
5 69 2073 2021-02-23 04:02:58.680 2021-03-23 04:02:58.680 1 2
6 70 2073 2021-03-22 23:39:33.570 2021-04-22 23:39:33.570 0 2
7 71 2073 2021-04-22 00:28:35.230 2021-05-22 00:28:35.230 0 2
8 72 2073 2021-05-22 15:46:21.767 2021-06-22 15:46:21.767 1 3
9 73 2073 2021-06-25 06:42:02.130 2021-07-25 06:42:02.130 1 4
10 76 2073 2021-07-23 17:42:01.533 2021-08-23 17:42:01.533 0 4
where working 的旧查询(生成上述样本):
SELECT
RN
, ReportId
, DriverId
, StartDate
, EndDate
, Level1Vio
, Lv1YTD = SUM(Level1Vio) OVER(PARTITION BY DriverId ORDER BY ReportId ROWS UNBOUNDED PRECEDING)
FROM Report
例外结果应该是(对于新要求):
RN ReportId DriverId StartDate EndDate Level1Vio Lv1YTD
-------------------- -------------------- -------------------- ----------------------- ----------------------- ----------- -----------
1 64 2073 2020-10-21 00:00:00.000 2020-11-21 23:59:59.000 1 1
2 65 2073 2020-11-24 05:13:04.133 2020-12-24 05:13:04.133 0 1
3 67 2073 2020-12-23 06:53:52.870 2021-01-23 06:53:52.870 0 1
4 68 2073 2021-01-22 06:33:43.127 2021-02-22 06:33:43.127 0 1
5 69 2073 2021-02-23 04:02:58.680 2021-03-23 04:02:58.680 1 2
6 70 2073 2021-03-22 23:39:33.570 2021-04-22 23:39:33.570 0 2
7 71 2073 2021-04-22 00:28:35.230 2021-05-22 00:28:35.230 0 1
8 72 2073 2021-05-22 15:46:21.767 2021-06-22 15:46:21.767 1 2
9 73 2073 2021-06-25 06:42:02.130 2021-07-25 06:42:02.130 1 3
10 76 2073 2021-07-23 17:42:01.533 2021-08-23 17:42:01.533 0 3
SQL Fiddle
说明
如果您采取 ReportId = 64
(2020 年 11 月报告) driver 已注册违规,应在 180 天后删除,然后在ReportId = 69
(2021 年 3 月报告) 再次违规。第一次违规应在 ReportId = 71
(2021 年 5 月报告) 结束,第二次违规应在 ReportId = 76
(2021 年 8 月报告)。该原则适用于每次违规。
尝试
实际上,我正在努力避免 cursor
和 while
循环,但是我找不到一种方法来在一个查询 SELECT
下执行此操作,就像我在上面的查询中所做的那样。我试过 CTE
并加入,但没有成功。一切都迫使我使用循环,我尽量避免循环(因为性能问题)。我确信有一种方法可以用简单的 SELECT
来解决它,但我没有想法。因此,我们将不胜感激任何想法或解决方案。
我们可以只加入重叠 180 天的记录,而不是 window 函数。
已更新 fiddle:Working Test Case
SELECT t1.rn, t1.ReportId, t1.DriverId, t1.StartDate, t1.EndDate, t1.Level1Vio
, SUM(t2.Level1Vio) AS Lv1YTD
FROM Report AS t1
JOIN Report AS t2
ON t1.StartDate BETWEEN t2.StartDate AND DATEADD(day, 180, t2.StartDate)
AND t1.DriverId = t2.DriverId
GROUP BY t1.rn, t1.DriverId, t1.ReportId, t1.StartDate, t1.EndDate, t1.Level1Vio
ORDER BY t1.StartDate
;
注意:我使用了从举报违规行为开始算起的 180 天。根据需要进行调整。
另请注意:我包含了一个使用 CTE 术语的版本。如果您希望更方便地过滤连接两侧感兴趣的行,将它们限制在特定年份,或者只是将该年份限制添加到连接逻辑或添加 WHERE
子句,则可以使用它。
有很多方法可以将年份逻辑全部包含在此查询中,而无需求助于每年生成单独的查询。
我有一个查询可以为 driver 的评估生成月度报告。一些 driver 可能几个月都没有报告。报告包含各种违规行为,其中一种违规行为是每月累计违规行为,并且每年 重新设置,这是在单独的查询 中完成的。一切工作都很好,除非客户向这部分添加了新要求。要求是将其从每年重置更改为重置一年中超过 180 天的任何违规行为。
这是一份报告的样本(一份 driver 报告):
RN ReportId DriverId StartDate EndDate Level1Vio Lv1YTD
-------------------- -------------------- -------------------- ----------------------- ----------------------- ----------- -----------
1 64 2073 2020-10-21 00:00:00.000 2020-11-21 23:59:59.000 1 1
2 65 2073 2020-11-24 05:13:04.133 2020-12-24 05:13:04.133 0 1
3 67 2073 2020-12-23 06:53:52.870 2021-01-23 06:53:52.870 0 1
4 68 2073 2021-01-22 06:33:43.127 2021-02-22 06:33:43.127 0 1
5 69 2073 2021-02-23 04:02:58.680 2021-03-23 04:02:58.680 1 2
6 70 2073 2021-03-22 23:39:33.570 2021-04-22 23:39:33.570 0 2
7 71 2073 2021-04-22 00:28:35.230 2021-05-22 00:28:35.230 0 2
8 72 2073 2021-05-22 15:46:21.767 2021-06-22 15:46:21.767 1 3
9 73 2073 2021-06-25 06:42:02.130 2021-07-25 06:42:02.130 1 4
10 76 2073 2021-07-23 17:42:01.533 2021-08-23 17:42:01.533 0 4
where working 的旧查询(生成上述样本):
SELECT
RN
, ReportId
, DriverId
, StartDate
, EndDate
, Level1Vio
, Lv1YTD = SUM(Level1Vio) OVER(PARTITION BY DriverId ORDER BY ReportId ROWS UNBOUNDED PRECEDING)
FROM Report
例外结果应该是(对于新要求):
RN ReportId DriverId StartDate EndDate Level1Vio Lv1YTD
-------------------- -------------------- -------------------- ----------------------- ----------------------- ----------- -----------
1 64 2073 2020-10-21 00:00:00.000 2020-11-21 23:59:59.000 1 1
2 65 2073 2020-11-24 05:13:04.133 2020-12-24 05:13:04.133 0 1
3 67 2073 2020-12-23 06:53:52.870 2021-01-23 06:53:52.870 0 1
4 68 2073 2021-01-22 06:33:43.127 2021-02-22 06:33:43.127 0 1
5 69 2073 2021-02-23 04:02:58.680 2021-03-23 04:02:58.680 1 2
6 70 2073 2021-03-22 23:39:33.570 2021-04-22 23:39:33.570 0 2
7 71 2073 2021-04-22 00:28:35.230 2021-05-22 00:28:35.230 0 1
8 72 2073 2021-05-22 15:46:21.767 2021-06-22 15:46:21.767 1 2
9 73 2073 2021-06-25 06:42:02.130 2021-07-25 06:42:02.130 1 3
10 76 2073 2021-07-23 17:42:01.533 2021-08-23 17:42:01.533 0 3
SQL Fiddle
说明
如果您采取 ReportId = 64
(2020 年 11 月报告) driver 已注册违规,应在 180 天后删除,然后在ReportId = 69
(2021 年 3 月报告) 再次违规。第一次违规应在 ReportId = 71
(2021 年 5 月报告) 结束,第二次违规应在 ReportId = 76
(2021 年 8 月报告)。该原则适用于每次违规。
尝试
实际上,我正在努力避免 cursor
和 while
循环,但是我找不到一种方法来在一个查询 SELECT
下执行此操作,就像我在上面的查询中所做的那样。我试过 CTE
并加入,但没有成功。一切都迫使我使用循环,我尽量避免循环(因为性能问题)。我确信有一种方法可以用简单的 SELECT
来解决它,但我没有想法。因此,我们将不胜感激任何想法或解决方案。
我们可以只加入重叠 180 天的记录,而不是 window 函数。
已更新 fiddle:Working Test Case
SELECT t1.rn, t1.ReportId, t1.DriverId, t1.StartDate, t1.EndDate, t1.Level1Vio
, SUM(t2.Level1Vio) AS Lv1YTD
FROM Report AS t1
JOIN Report AS t2
ON t1.StartDate BETWEEN t2.StartDate AND DATEADD(day, 180, t2.StartDate)
AND t1.DriverId = t2.DriverId
GROUP BY t1.rn, t1.DriverId, t1.ReportId, t1.StartDate, t1.EndDate, t1.Level1Vio
ORDER BY t1.StartDate
;
注意:我使用了从举报违规行为开始算起的 180 天。根据需要进行调整。
另请注意:我包含了一个使用 CTE 术语的版本。如果您希望更方便地过滤连接两侧感兴趣的行,将它们限制在特定年份,或者只是将该年份限制添加到连接逻辑或添加 WHERE
子句,则可以使用它。
有很多方法可以将年份逻辑全部包含在此查询中,而无需求助于每年生成单独的查询。