【问题标题】:Split Overlapping\Merged Dates in SQL在 SQL 中拆分重叠\合并日期
【发布时间】:2021-04-01 19:22:39
【问题描述】:

我有一个要求,我必须将给定表上的重叠记录拆分为 2 个日期字段。

认为这是我的输入表 TableT。

ID EFFECTIVE_DATE END_DATE
JKL 2016-01-01 2016-12-31
JKL 2016-04-01 2016-12-31
JKL 2016-01-01 2016-03-04
JKL 2016-04-01 2016-12-31
JKL 2016-01-01 2016-12-31

我希望我的输出如下所示。我需要在 SQL Server 和 Oracle\DB2 中实现这一点,所以我正在寻找一个通用的解决方案。

ID EFFECTIVE_DATE END_DATE
JKL 2016-01-01 2016-03-04
JKL 2016-03-05 2016-03-31
JKL 2016-04-01 2016-12-31

这是我尝试过的

With EndDates as (
    select END_DATE as END_DATE,TRIM(ID) as ID  FROM TableT  
    union all
    select ADD_DAYS(EFFECTIVE_DATE, -1) as END_DATE,TRIM(ID) as ID FROM TableT 
), Periods as (
    select ID as ID,MIN(EFFECTIVE_DATE) as EFFECTIVE_DATE,
                (select MIN(END_DATE) from EndDates e
                 where e.ID = t.ID and
                 e.END_DATE >= MIN(EFFECTIVE_DATE)) as END_DATE
    from
        TableT t  
    group by ID),
    EXTN_PERIOD as (select p.ID as ID, ADD_DAYS(p.END_DATE, 1) as EFFECTIVE_DATE,e.END_DATE as END_DATE
    from
        Periods p
            inner join
        EndDates e
            on
                p.ID = e.ID and
                p.END_DATE < e.END_DATE
    where
        not exists (select * from EndDates e2 where
                e2.ID = p.ID and
                e2.END_DATE > p.END_DATE and
                e2.END_DATE < e.END_DATE)
)
select * from EXTN_PERIOD
union
select * from PERIODS

它部分工作正常,但没有给我想要的输出。

这是我运行上述查询时得到的输出:

ID EFFECTIVE_DATE END_DATE
JKL 2016-01-01 2016-03-04
JKL 2016-03-05 2016-03-31

提前致谢!

【问题讨论】:

  • 这需要在 2 个 rdbms sqlserver 和 oracle(或)db2 中实现解决方案。我只标记了必需的 rdbms
  • 在您提供的示例中,您只有 1 个重叠的日期范围,即 2016-01-01 到 2016-12-31。您会有多个重叠的日期范围吗?

标签: sql sql-server oracle db2


【解决方案1】:
WITH 
/*
MY_TAB (ID, EFFECTIVE_DATE, END_DATE) AS
(
VALUES
  ('JKL', DATE('2016-01-01'), DATE('2016-12-31'))
, ('JKL', DATE('2016-04-01'), DATE('2016-12-31'))
, ('JKL', DATE('2016-01-01'), DATE('2016-03-04'))
, ('JKL', DATE('2016-04-01'), DATE('2016-12-31'))
, ('JKL', DATE('2016-01-01'), DATE('2016-12-31'))
)
, 
*/ 
A AS 
(
SELECT DISTINCT T.ID, DECODE(V.I, 1, T.EFFECTIVE_DATE, 2, T.END_DATE + 1) DT
FROM MY_TAB T, (VALUES 1, 2) V(I)
)
, INTL AS 
(
SELECT 
  ID
, LAG(DT) OVER (PARTITION BY ID ORDER BY DT) AS EFF_DT
, DT AS END_DT
FROM A
)
SELECT ID, EFF_DT, END_DT - 1 AS END_DT
FROM INTL
WHERE EFF_DT IS NOT NULL
ORDER BY 1, 2;

几乎是通用的。唯一的自定义是生成具有 2 行(具有 INTEGERS 1 和 2)的关联名称 V 的“虚拟”表的方式。
这个想法是首先将您的数据转换为 [inclusive,exclusive] 形式以简化进一步的计算。然后我们合并所有生效日期和结束日期,并使用 OLAP LAG 函数构建间隔。最后,我们恢复为您的 [inclusive, inclusive] 表格。

db<>fiddle 测试链接。

【讨论】:

    【解决方案2】:

    在 Oracle 中,您可以这样做:

    with
      tablet (id, effective_date, end_date) as (
        select 'JKL',   date '2016-01-01', date '2016-12-31' from dual union all
        select 'JKL',   date '2016-04-01', date '2016-12-31' from dual union all
        select 'JKL',   date '2016-01-01', date '2016-03-04' from dual union all
        select 'JKL',   date '2016-04-01', date '2016-12-31' from dual union all
        select 'JKL',   date '2016-01-01', date '2016-12-31' from dual
      )
    , prep (id, dt) as (
        select  distinct id, case col when 'EFF' then val else val + 1 end
        from    tablet
        unpivot (val for col in (effective_date as 'EFF', end_date as 'END'))
      )
    , almost_done (id, effective_date, end_date) as (
        select id, dt, lead(dt) over (partition by id order by dt) - 1
        from   prep
      )
    select id, effective_date, end_date
    from   almost_done
    where  end_date is not null
    ;
    
    ID  EFFECTIVE_DATE END_DATE  
    --- -------------- ----------
    JKL 2016-01-01     2016-03-04
    JKL 2016-03-05     2016-03-31
    JKL 2016-04-01     2016-12-31
    

    请注意第一个 CTE(tablet,用于生成测试数据 - 在您的实际案例中不需要它)。然后,第一步是对数据进行反透视;我不知道 SQL Server 如何支持反透视,最坏的情况是您可以使用交叉连接手动完成。 (不适用于UNION ALL - 效率低下。)然后您删除重复项,其余的很容易使用LEAD 分析函数,SQL Server 也应该支持。

    【讨论】:

      猜你喜欢
      • 2020-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-10
      相关资源
      最近更新 更多