我的桌子的日期是2015年11月2日至2015年12月1日。 例如...
ATTNDATE
--------
02/11/2015
03/11/2015
--
--
--
01/12/2015.
这张表也可能有一些缺失的日期..让我们假设这张表中缺少06/11/2015和20/11/2015。
我希望得到像
这样的输出SL.No ATTNFROM ATTNTILL
1. 02/11/2015 05/11/2015
2. 07/11/2015 19/11/2015
3. 21/11/2015 01/12/2015
请帮我在oracle plsql中获取此输出
答案 0 :(得分:6)
您可以使用超前和滞后分析函数 - 在子组中进行分组,然后将其分组,这可能是您错过的 - 但您也可以使用分析'技巧来实现。
如果你看看每个日期和最低日期之间的区别,你会得到一个破碎的序列,在你的情况下是0,1,2,3,5,......,27,28,29。你可以看到attndate - min(attndate) over ()
。
你还可以从row_number() over (order by attndate)
获得另一个不间断的序列,它可以提供1,2,3 ...... 28。
如果从另一个中减去一个,则每个连续的日期块都会得到相同的答案,我称之为“slot_no'”
select attndate,
attndate - min(attndate) over ()
- row_number() over (order by attndate) as slot_no
from your_table;
使用这些数据,每一行都会得到-1,0或1.(如果需要,可以添加两行以使它们更友好,但只有在数据中的间隙为单日时才能正常工作)。然后,您可以按该插槽编号进行分组:
with cte as (
select attndate,
attndate - min(attndate) over ()
- row_number() over (order by attndate) as slot_no
from your_table
)
select dense_rank() over (order by slot_no) as slot_no,
min(attndate) as attnfrom, max(attndate) as attntill
from cte
group by slot_no
order by slot_no;
使用一些生成的数据:
alter session set nls_date_format = 'DD/MM/YYYY';
with your_table (attndate) as (
select date '2015-11-02' + level - 1 from dual connect by level <= 4
union all select date '2015-11-07' + level - 1 from dual connect by level <= 13
union all select date '2015-11-21' + level - 1 from dual connect by level <= 11
),
cte as (
select attndate,
attndate - min(attndate) over ()
- row_number() over (order by attndate) as slot_no
from your_table
)
select dense_rank() over (order by slot_no) as slot_no,
min(attndate) as attnfrom, max(attndate) as attntill
from cte
group by slot_no
order by slot_no;
SLOT_NO ATTNFROM ATTNTILL
---------- ---------- ----------
1 02/11/2015 05/11/2015
2 07/11/2015 19/11/2015
3 21/11/2015 01/12/2015
如果您的真实场景是获取多个键的这些范围,例如人员ID,那么您可以在三个partition by
部分中为每个分析函数调用添加over ()
子句。 / p>