获取多个ID的两个日期之间的天数

Getting the days between two dates for multiple IDs

这是 How to get a list of months between 2 given dates using a query? 的跟进问题 真的。 (我怀疑是因为我不太明白connect by level子句背后的逻辑!)

我拥有的是这样的数据列表

ID | START_DATE  | END_DATE
 1 | 01-JAN-2018 | 20-JAN-2018
 2 | 13-FEB-2018 | 20-MAR-2018
 3 | 01-MAR-2018 | 07-MAR-2018

我想要尝试获取的是一个列表,其中包含每个 ID 的开始日期和结束日期之间的所有天数。

所以例如我想要一个列表

ID | DATE
 1 | 01-JAN-2018
 1 | 02-JAN-2018
 1 | 03-JAN-2018 
...
 1 | 19-JAN-2018
 1 | 20_JAN-2018
 2 | 13-FEB-2018
 2 | 14-FEB-2018
 2 | 15-FEB-2018 
...

等等

我尝试做的是将上述 link 中的一个答案改编如下

select id
, trunc(start_date+((level-1)),'DD') 
from (
  select id
  , start_date
  , end_date
  from blah
 ) 
connect by level <= ((trunc(end_date,'DD')-trunc(start_date,'DD'))) + 1

这给了我想要的东西,但随后出现了一大堆重复的日期,就像笛卡尔连接一样。我需要添加一些简单的东西来解决这个问题吗?

我喜欢递归 CTE:

with cte as (
      select id, start_dte as dte, end_dte
      from blah
      union all
      select id, dte + 1, end_dte
      from cte
      where dte < end_dte
     )
select *
from cte
order by id, dte;

这是 ANSI 标准语法,适用于其他几个数据库。

您尝试执行的分层查询需要在 connect-by 子句中包含 id = prior id,但由于这会导致包含多个源行的循环,您还需要包含对非确定性函数的调用, 例如 dbms_random.value:

select id, start_date + level - 1 as day
from blah
connect by level <= end_date - start_date + 1
and prior id = id
and prior dbms_random.value is not null

使用 CTE 中的样本数据,返回 63 行:

with blah (ID, START_DATE, END_DATE) as (
            select 1, date '2018-01-01', date '2018-01-20' from dual
  union all select 2, date '2018-02-13', date '2018-03-20' from dual
  union all select 3, date '2018-03-01', date '2018-03-07' from dual
)
select id, start_date + level - 1 as day
from blah
connect by level <= end_date - start_date + 1
and prior id = id
and prior dbms_random.value is not null;

        ID DAY       
---------- ----------
         1 2018-01-01
         1 2018-01-02
         1 2018-01-03
...
         1 2018-01-19
         1 2018-01-20
         2 2018-02-13
         2 2018-02-14
...
         3 2018-03-05
         3 2018-03-06
         3 2018-03-07

您不需要 trunc() 日期,除非它们有非午夜时间,这在这种情况下似乎不太可能,即使这样也可能没有必要,如果只有结束日期有更晚的时间时间(如 23:59:59)。

不过,递归 CTE 在很多方面都更直观,至少在您理解了它们的基本思想之后;所以我可能也会使用戈登的方法。性能可能存在差异,它们是否适用于大量数据(或生成的行),但对于大量数据,值得比较不同的方法以找到最多 suitable/performant。