ORACLE SQL:根据日期范围创建新行

时间:2021-04-28 20:07:57

标签: sql oracle date

例如,我有一个表名 test_cross_months,数据如下:

<头>
id 开始日期 结束日期
44 2020-01-04 2020-01-04
44 2020-01-30 2020-02-10
44 2020-02-27 2020-03-03

预期结果:

<头>
id 开始日期 结束日期
44 2020-01-04 2020-01-04
44 2020-01-30 2020-01-31
44 2020-02-01 2020-02-10
44 2020-02-27 2020-02-29
44 2020-03-01 2020-03-03

所以对于 |44|2020-01-30 |2020-02-10| 应该有两行,从 30-Jan-2020 到 31-Jan-2020 和 1-Feb-2020 到 10-Feb-2020

我尝试将结束日期与 start_date 的最后一天进行比较,但由于没有为 end_date 范围创建新行而面临问题。

有没有人可以提出解决方案?

2 个答案:

答案 0 :(得分:2)

您可以使用递归查询(无论您的范围跨越多少个月都可以使用):

WITH months ( id, start_date, end_date, final_date ) AS (
  SELECT id,
         start_date,
         LEAST( LAST_DAY( start_date ), end_date ),
         end_date
  FROM   table_name
UNION ALL
  SELECT id,
         end_date + INTERVAL '1' DAY,
         LEAST( ADD_MONTHS( end_date, 1 ), final_date ),
         final_date
  FROM   months
  WHERE  end_date < final_date
)
SEARCH DEPTH FIRST BY final_date SET dt_order
SELECT id,
       start_date,
       end_date
FROM   months;

对于样本数据:

CREATE TABLE table_name (id, start_date, end_date) AS
SELECT 44, DATE '2020-01-04', DATE '2020-01-04' FROM DUAL UNION ALL
SELECT 44, DATE '2020-01-30', DATE '2020-02-10' FROM DUAL UNION ALL
SELECT 44, DATE '2020-02-27', DATE '2020-03-03' FROM DUAL;

输出:

<块引用>
<头>
ID START_DATE END_DATE
44 2020-01-04 00:00:00 2020-01-04 00:00:00
44 2020-01-30 00:00:00 2020-01-31 00:00:00
44 2020-02-01 00:00:00 2020-02-10 00:00:00
44 2020-02-27 00:00:00 2020-02-29 00:00:00
44 2020-03-01 00:00:00 2020-03-03 00:00:00

db<>fiddle here

答案 1 :(得分:0)

使用数字表和日期算术

-- example of table of numbers
with nmbrs(n) as(
   select 0 from dual union all
   select 1 from dual union all
   select 2 from dual 
)
select t.id, 
   case when n=0 then t.start_date else trunc(t.start_date, 'MM') + NUMTOYMINTERVAL(n, 'MONTH') end s,
   case when n=MONTHS_BETWEEN(last_day(t.end_date), last_day(t.start_date)) then t.end_date 
       else last_day(t.start_date + NUMTOYMINTERVAL(n, 'MONTH')) end e
from test_cross_months t
join nmbrs on nmbrs.n <= MONTHS_BETWEEN(last_day(t.end_date), last_day(t.start_date))
order by t.id, s 

db<>fiddle