啰嗦: 其实很早就遇到过类似问题,也设想过,不过一致没实际业务需求,也就耽搁了;最近有业务提到了,和同事讨论,各有想法,所以先把逻辑整理出来,希望有更好更优的解决方案;
背景:
某业务配置表,按配置的时间区间及组织层级取方案,形成报表展示出所有部门方案的取值;
例如,总公司配置20230101-20231231为方案3, 分公司配置 20230301-20230731 为方案2,部门配置20230601-20231031 为方案1,配置优先级为 部门> 分公司>总公司 ,即啥都没配则使用总公司默认值;
分析: 如果是单天计算, 那很简单,可以直接按天匹配,然后取 方案1> 方案2> 方案3;
现在要展示,讨论有2种方案,1.区间完全切割开,形成最小时间区间,进行取值;2.放临时表,从低优先级开始,进行不断迭代覆盖;
这里主要展示方案1, 主要感觉方案1可以直接查询出来,应该是比较简单的;
直接贴代码
WITH A AS --基础数据
(SELECT 3 AS LEVE, '20230101' AS BEGINDATE, '20231231' AS ENDDATE
FROM DUAL
UNION ALL
SELECT 2 AS LEVE, '20230301' AS BEGINDATE, '20230731' AS ENDDATE
FROM DUAL
UNION ALL
SELECT 1 AS LEVE, '20230601' AS BEGINDATE, '20231031' AS ENDDATE
FROM DUAL),
B AS --开始日期和截止日期合并一列
(SELECT BEGINDATE AS DAY FROM A UNION SELECT ENDDATE FROM A ORDER BY DAY),
C AS --生产日期节点前后一天,将时间边界当天天单独作为一条记录
(SELECT DAY,
TO_CHAR(TO_DATE(DAY, 'yyyyMMdd') - 1, 'yyyyMMdd') AS DAY_LAST,
TO_CHAR(TO_DATE(DAY, 'yyyyMMdd') + 1, 'yyyyMMdd') AS DAY_NEXT,
ROWNUM N
FROM B),
D AS --生成最小的时间区间,并关联各个时间边界当天
(SELECT C1.DAY_NEXT AS BEGINDATE, C2.DAY_LAST AS ENDDATE
FROM C C1, C C2
WHERE C1.N + 1 = C2.N
UNION
SELECT DAY AS BEGINDATE, DAY AS ENDDATE
FROM C
ORDER BY BEGINDATE)
--最后进行查询匹配, 权重取最小
SELECT D.*, MIN(A.LEVE) AS LEVE
FROM D
LEFT JOIN A
ON D.BEGINDATE >= A. BEGINDATE
AND D.ENDDATE <= A.ENDDATE
GROUP BY D.BEGINDATE, D.ENDDATE
ORDER BY D.BEGINDATE, D.ENDDATE
执行结果 :
PS: 由于时间区间边界当天,不好判断,只能单独拉出来作为一条记录, 虽然保证了边界数据的准确性,但拆分太散后 无法合并到一起,
方便的话,告知下合并的方式,再此特别感谢。