根据 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
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