Dav*_*ill 4 sql oracle gaps-and-islands
我在一个字段中有一个表(包括其他内容)日期.
我需要获取所有日期的列表,这些日期比最早的日期更新,比最近的日期更早,并且在表格中完全丢失.
所以,如果表包含:
2012-01-02
2012-01-02
2012-01-03
2012-01-05
2012-01-05
2012-01-07
2012-01-08
Run Code Online (Sandbox Code Playgroud)
我想要一个返回的查询:
2012-01-04
2012-01-06
Run Code Online (Sandbox Code Playgroud)
a_h*_*ame 13
这样的事情(假设你的表被命名your_table
并且日期列被命名the_date
):
with date_range as (
select min(the_date) as oldest,
max(the_date) as recent,
max(the_date) - min(the_date) as total_days
from your_table
),
all_dates as (
select oldest + level - 1 as a_date
from date_range
connect by level <= (select total_days from date_range)
)
select ad.a_date
from all_dates ad
left join your_table yt on ad.a_date = yt.the_date
where yt.the_date is null
order by ad.a_date;
Run Code Online (Sandbox Code Playgroud)
编辑:
该WITH
子句称为"公用表表达式",相当于派生表("内联视图").
它类似于
select *
from (
.....
) all_dates
join your_table ...
Run Code Online (Sandbox Code Playgroud)
第二个CTE使用Oracle connect by
实现的未记录功能简单地"动态"创建日期列表.
重复使用select(就像我计算第一个和最后一个日期一样)比使用派生表更容易(和IMHO更易读).
编辑2:
这也可以通过递归CTE完成:
with date_range as (
select min(the_date) as oldest,
max(the_date) as recent,
max(the_date) - min(the_date) as total_days
from your_table
),
all_dates (a_date, lvl) as (
select oldest as a_date, 1 as lvl
from date_range
union all
select (select oldest from date_range) + lvl, lvl + 1
from all_dates
where lvl < (select total_days from date_range)
)
select ad.a_date, lvl
from all_dates ad
left join your_table yt on ad.a_date = yt.the_date
where yt.the_date is null
order by ad.a_date;
Run Code Online (Sandbox Code Playgroud)
这应该适用于所有支持递归CTE的DBMS(PostgreSQL和Firebird - 更符合标准 - recursive
尽管需要关键字).
注意select (select oldest from date_range) + lvl, lvl + 1
递归部分中的hack .这不应该是必要的,但Oracle在递归CTE中仍有一些关于DATE的错误.在PostgreSQL中,以下工作没有问题:
....
all_dates (a_date, lvl) as (
select oldest as a_date, 0 as lvl
from date_range
union all
select a_date + 1, lvl + 1
from all_dates
where lvl < (select total_days from date_range)
)
....
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
4268 次 |
最近记录: |