自学内容网 自学内容网

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)!