【问题标题】:Split records based on date in sql根据sql中的日期拆分记录
【发布时间】:2021-01-14 22:40:20
【问题描述】:

ID EFF_DT END_DT

FLA1 2018-01-01 00:00:00 2019-12-31 00:00:00

FLA1 2020-01-01 00:00:00 9999-12-31 00:00:00

以上结构需要拆分。并且拆分应该基于日期。

输出应该有额外的列作为年份

ID EFF_DT END_DT YEAR

FLA1 2018-01-01 00:00:00 2019-12-31 00:00:00 2019

FLA1 2020-01-01 00:00:00 2020-12-31 00:00:00 2020

FLA1 2021-01-01 00:00:00 9999-12-31 00:00:00 2021

我为此目的使用联合,它正在生成重复项。任何其他方法/改进解决方案都可以。提前致谢。

【问题讨论】:

  • 为什么第二行(来自“上面的结构”)被分成两行?为什么不进入 9999 - 2020 = 7979 行?哪些规则从输入引导到期望的输出?
  • 上一年应该是记录 1 ,记录 2 应该是当前一年,记录 3 应该是未来一年

标签: sql oracle datetime join union


【解决方案1】:

如果要生成所有年的数据,那么:

with cte (id, eff_dt, end_dt, orig_end_dt)
      select id, eff_dt, end_dt, end_dt
      from t
      union all
      select cte.id, end_dt + interval '1' day,
             least(orig_end_dte, trunc(end_dt, 'YYYY') + interval '1' year
      from cte
      where trunc(eff_dt, 'YYYY') < trunc(end_dt, 'YYYY')
     )
select id, eff_dt, end_dt, to_char(end_dt, 'YYYY') as year
from cte;

注意:这会为该期间的每一年生成一个单独的行。

如果您想要对年份进行限制,那么它将是这样的:

with cte (id, eff_dt, end_dt, orig_end_dt)
      select id, eff_dt, end_dt, end_dt
      from t
      union all
      select cte.id, end_dt + interval '1' day,
             least(orig_end_dte, trunc(end_dt, 'YYYY') + interval '1' year
      from cte
      where trunc(eff_dt, 'YYYY') < least(trunc(end_dt, 'YYYY'), date '2021-01-01')
     )
select id, eff_dt,
       (case when end_dt = date '2021-12-31' then orig_end_dt else end_dt end),
       to_char(end_dt, 'YYYY') as year
from cte;

【讨论】:

    【解决方案2】:

    您可以使用递归子查询分解子句:

    WITH split ( ID, EFF_DT, END_DT, MAX_DT ) AS (
      SELECT id, 
             eff_dt,
             LEAST(
               ADD_MONTHS( TRUNC( SYSDATE, 'YY' ), 12 ) - INTERVAL '1' DAY,
               end_dt
             ),
             end_dt
      FROM   table_name
    UNION ALL
      SELECT id,
             end_dt + INTERVAL '1' DAY,
             max_dt,
             max_dt
      FROM   split
      WHERE  end_dt < max_dt
    )
    SELECT id,
           eff_dt,
           end_dt
    FROM   split;
    

    对于您的示例数据:

    CREATE TABLE table_name ( ID, EFF_DT, END_DT ) AS
    SELECT 'FLA1', DATE '2018-01-01', DATE '2019-12-31' FROM DUAL UNION ALL
    SELECT 'FLA1', DATE '2020-01-01', DATE '9999-12-31' FROM DUAL;
    

    输出:

    身份证 | EFF_DT | END_DT :--- | :----------------- | :----------------- FLA1 | 2018-01-01 00:00:00 | 2019-12-31 00:00:00 FLA1 | 2020-01-01 00:00:00 | 2020-12-31 00:00:00 FLA1 | 2021-01-01 00:00:00 | 9999-12-31 00:00:00

    db小提琴here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多