这是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
这给了我我想要的东西,但是又提供了很多重复的日期,就好像是笛卡尔联接一样。我需要添加一些简单的方法来解决此问题吗?
答案 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的基本概念之后,它在许多方面都更加直观。所以我可能也会使用戈登的方法。在性能以及它们是否适用于大量数据(或生成的行)方面可能存在差异,但是对于大量数据,还是值得比较不同的方法以找到最合适的/性能最佳的。