根据 sql 中的日期拆分记录

Split records based on date in sql

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

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

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

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;

您可以使用递归 sub-query 分解子句:

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;

输出:

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 | 2020-12-31 00:00:00
FLA1 | 2021-01-01 00:00:00 | 9999-12-31 00:00:00

db<>fiddle here