Oracle - 多区间按权重取值逻辑 ,分时区-多层级-取配置方案(三)
本篇紧跟第一篇, 和 第二篇无关
Oracle - 多区间按权重取值逻辑 ,分时区-多层级-取配置方案
Oracle - 多区间按权重取值逻辑 ,分时区-多层级-取配置方案(二)
先说需求:
某业务配置表,按配置的时间区间及组织层级取方案,形成报表展示出所有部门方案的取值;
例如,总公司配置20230101-20231231为方案3, 分公司配置 20230301-20230731 为方案2,部门配置20230601-20231031 为方案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 2 AS LEVE, '20231001' AS BEGINDATE, '20231130' AS ENDDATE
FROM DUAL
UNION ALL
SELECT 1 AS LEVE, '20230201' AS BEGINDATE, '20230831' AS ENDDATE
FROM DUAL)
--SELECT * FROM A ORDER BY A.BEGINDATE
, 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 (SELECT BEGINDATE AS DAY FROM A UNION SELECT ENDDATE FROM A ORDER BY DAY)),
--最后进行查询匹配, 权重取最小
E AS
(SELECT D.*, MIN(A.LEVE) AS LEVE
FROM (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) 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)
--分段进行汇总
,
F AS
(SELECT NVL(C.DAY, E.BEGINDATE) AS BEGINDATE, NVL(C2.DAY, E.ENDDATE) AS ENDDATE, E.LEVE
FROM E
LEFT JOIN C
ON E.BEGINDATE <> E.ENDDATE
AND E.BEGINDATE = C.DAY_NEXT
AND EXISTS (SELECT 1
FROM E E2
WHERE E2.BEGINDATE = E2.ENDDATE
AND E2.BEGINDATE = C.DAY
AND E.LEVE = E2.LEVE)
LEFT JOIN C C2
ON E.BEGINDATE <> E.ENDDATE
AND E.ENDDATE = C2.DAY_LAST
AND EXISTS (SELECT 1
FROM E E2
WHERE E2.BEGINDATE = E2.ENDDATE
AND E2.ENDDATE = C2.DAY
AND E.LEVE = E2.LEVE)
ORDER BY E.LEVE, E.BEGINDATE)
--去掉边界日期
,
G AS
(SELECT F.*, ROWNUM N
FROM F
WHERE F.BEGINDATE <> F.ENDDATE
OR NOT EXISTS
(SELECT 1
FROM F F2
WHERE F2.BEGINDATE = F2.ENDDATE
AND F2.LEVE = F.LEVE
AND (F2.BEGINDATE = F. BEGINDATE OR F2.BEGINDATE = F. ENDDATE))
ORDER BY BEGINDATE),
H(B1,
E1,
L1) AS
(SELECT BEGINDATE, ENDDATE, LEVE
FROM G
WHERE G.BEGINDATE NOT IN (SELECT ENDDATE FROM G)
UNION ALL
SELECT H.B1, H2.ENDDATE AS E1, H.L1
FROM H
JOIN G H2
ON H.E1 = H2.BEGINDATE
AND H.L1 = H2.LEVE)
SELECT B1, MAX(E1), L1 FROM H GROUP BY B1, L1;
原文地址:https://blog.csdn.net/shijianduan1/article/details/143906085
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!