获取多个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。
这是 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。