获取两个ID之间的两个日期之间的日期

时间:2018-07-04 14:54:11

标签: sql oracle oracle12c hierarchical-query

这是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 
...

我试图做的是如下调整上面链接的答案之一

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

这给了我我想要的东西,但是又提供了很多重复的日期,就好像是笛卡尔联接一样。我需要添加一些简单的方法来解决此问题吗?

2 个答案:

答案 0 :(得分:2)

我喜欢递归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标准语法,可在其他几个数据库中使用。

答案 1 :(得分:0)

您尝试执行的分层查询需要在connect-by子句中包含<?xml version="1.0" encoding="utf-8"?> <configuration> <components> <component id="myConfiguration" service="Application.IMyConfiguration, Application" type="Application.MyConfiguration, Application"> <parameters> <Url>example.com</Url> <Token>00000000-0000-0000-0000-000000000000</Token> <Mapping> <dictionary> <entry key="AA"> <dictionary> <entry key="aa">00000000-0000-0000-0000-000000000000</entry> <entry key="bb">00000000-0000-0000-0000-000000000000</entry> <entry key="cc">00000000-0000-0000-0000-000000000000</entry> </dictionary> </entry> <entry key="BB"> <dictionary> <entry key="aa">00000000-0000-0000-0000-000000000000</entry> <entry key="bb">00000000-0000-0000-0000-000000000000</entry> <entry key="cc">00000000-0000-0000-0000-000000000000</entry> </dictionary> </entry> </dictionary> </Mapping> </parameters> </component> </components> </configuration> ,但是由于这会导致具有多个源行的循环,因此您还需要包括对非确定性函数的调用,例如为id = prior id

dbms_random.value

将您的示例数据放在CTE中,可以返回63行:

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

除非日期为非午夜时间,否则您无需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 ,这在这种情况下似乎不太可能,即使只有结束日期的时间晚一些,即使这样,也没有必要(像23:59:59)。

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