我有一个包含以下列的表:
ID | START_DATE | END_DATE
1001 | 02/02/2023 | 03/05/2023
1001 | 03/07/2023 | 11/05/2023
1002 | 03/05/2023 | 10/20/2023
1003 | 03/07/2023 | 04/07/2023
1004 | 04/07/2023 | 04/17/2023
1005 | 04/18/2023 | 05/19/2023
1006 | 05/19/2023 | 06/14/2023
1007 | 05/24/2023 | 06/28/2023
1008 | 10/31/2022 | 12/01/2022
1008 | 12/03/2022 | 10/07/2023
1009 | 12/01/2022 | 03/22/2023
1010 | 04/03/2023 | 05/04/2023
1011 | 05/04/2023 | 05/23/2023
1012 | 05/23/2023 | 10/02/2023
1013 | 06/15/2023 | 07/21/2023
1014 | 01/27/2023 | 02/07/2023
1015 | 05/02/2023 | 05/18/2023
1016 | 05/18/2023 | 06/18/2023
1017 | 06/18/2023 | 07/27/2023
1018 | 05/01/2023 | 09/30/2023
1019 | 11/22/2022 | 02/22/2023
1020 | 02/02/2022 | 05/04/2023
对于 12 个月的时间段(可能包括任何 12 个月的时间段),我需要每个月所有日平均值的摘要。
最终产品看起来像这样:
Month Daily Ave.
Oct-22 37.6
Nov-22 37.9
Dec-22 24.1
Jan-23 26.5
Feb-23 24.0
Mar-23 35.8
Apr-23 35.2
May-23 31.8
Jun-23 26.5
Jul-23 20.1
Aug-23 23.0
Sep-23 33.2
此表包含两个日期之间“活动”的 ID。
该表还包含重复的 ID,因为某个 ID 在多个时间段内处于“活动”状态。
在任何给定的一天中,应该只有一个“活动”的唯一 ID,但我猜想可能存在错误的数据来解释“活动”天重叠的情况。如果是的话,每天最多只计算一次ID。
要确定每月的每日平均值,请首先计算该月每一天所有“活跃”ID 的每日计数,然后将这些每日计数加在一起,然后除以该月的天数。
需要在该范围内的 12 个月中的每一个月重复此操作。
如果你手动计算这个,它会像......
检查日期范围与 2022 年 10 月 1 日相匹配的所有 ID,然后记录该计数。
本月所有日期重复上述步骤:10/2、10/3、10/4 等。
将上述步骤每天的所有总数相加,然后除以该月的 # 天。
对该范围内的每个月重复上述每个步骤。
其他注意事项:
-月份为日历月份(例如 10/1/2022 至 10/31/2022) -月份绝不是滚动月份(例如 11/10/2022 至 12/10/2022) -任何 ID 的“有效”开始日期可能会回溯多年,因此您无法将开始日期与您在请求的可报告范围内使用的月份关联起来。
通过 SQL(尤其是 DB2 风格的 SQL)可能有什么解决方案?
我创建了一个复杂的方法,通过 SQL 导出到 Excel,并为每天和每月以及所有 ID 创建公式数组(无论是否重复),该方法会提取数据并执行简单的 0 或 1 计数。在另一个选项卡中以类似的方式重复此操作,仅获取唯一 ID 的列表,以说明具有多个“活动”日期范围的 ID 的重复列表。这很麻烦并且容易出现人为错误。
您需要一个日期表,或者如下所示的 CTE 来生成所需的日期范围,然后将您的数据加入其中。这将允许您从开始日期到结束日期传播 id,然后使用 count(distinct ...) 从最终结果中删除重复项。
WITH dates (dt) AS (
SELECT DATE('2022-10-01') AS dt
FROM SYSIBM.SYSDUMMY1
UNION ALL
SELECT dt + 1 DAYS
FROM dates
WHERE dt < '2023-09-30'
)
SELECT
YEAR(d.dt) AS year
, MONTH(d.dt) AS month
, COUNT(DISTINCT t.ID) cd_tid
, COUNT(DISTINCT d.dt) cd_ddt
, (COUNT(DISTINCT t.ID) * 1.0) / (COUNT(DISTINCT d.dt) * 1.0) AS Daily_Ave
FROM dates d
LEFT JOIN ActiveIDs t ON d.dt BETWEEN t.START_DATE AND t.END_DATE
GROUP BY
YEAR(d.dt)
, MONTH(d.dt)
ORDER BY
YEAR(d.dt)
, MONTH(d.dt)
年份 | 月 | CD_TID | CD_滴滴涕 | DAILY_AVE |
---|---|---|---|---|
2022 | 10 | 2 | 31 | 0.064516129032258064 |
2022 | 11 | 3 | 30 | 0.100000000000000000 |
2022 | 12 | 4 | 31 | 0.129032258064516129 |
2023 | 1 | 5 | 31 | 0.161290322580645161 |
2023 | 2 | 6 | 28 | 0.214285714285714285 |
2023 | 3 | 6 | 31 | 0.193548387096774193 |
2023 | 4 | 8 | 30 | 0.266666666666666666 |
2023 | 5 | 13 | 31 | 0.419354838709677419 |
2023 | 6 | 10 | 30 | 0.333333333333333333 |
2023 | 7 | 7 | 31 | 0.225806451612903225 |
2023 | 8 | 5 | 31 | 0.161290322580645161 |
2023 | 9 | 5 | 30 | 0.166666666666666666 |
nb:您可以创建一个日历表,而不是每次都使用递归 CTE,这也可以通过索引受益。
另请参阅工作查询https://dbfiddle.uk/A10ZvRPg