需要Oracle sql查询来分组日期

时间:2016-01-27 11:36:46

标签: sql oracle oracle11g gaps-and-islands

我的桌子的日期是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中获取此输出

1 个答案:

答案 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>