oracle约会小组

时间:2017-02-01 17:05:51

标签: sql oracle date

如何获得此

的优化查询
date_one   | date_two 
------------------------
01.02.1999 | 31.05.2003
01.01.2004 | 01.01.2010
02.01.2010 | 10.10.2011 
11.10.2011 | (null)     

我需要得到这个

date_one   | date_two   | group 
------------------------------------
01.02.1999 | 31.05.2003 | 1
01.01.2004 | 01.01.2010 | 2
02.01.2010 | 10.10.2011 | 2
11.10.2011 | (null)     | 2

组号分配如下。按行date_one升序排序。第一行获得group = 1。然后,如果date_one是前一行date_two之后的日期,那么对于每一行,group数字与previous行中的相同,否则增加1

2 个答案:

答案 0 :(得分:1)

您可以使用left join和累积总和来执行此操作:

select t.*, sum(case when tprev.date_one is null then 1 else 0 end) over (order by t.date_one) as grp
from t left join
     t tprev
     on t.date_one = tprev.date_two + 1;

我们的想法是找到差距开始的位置(使用左连接),然后对这些开头进行累积求和以定义组。

如果你想要更加不可思议,你可以写成:

select t.*,
       count(*) over (order by t.date_one) - count(tprev.date_one) over (order by t.date_one) as grp
from t left join
     t tprev
     on t.date_one = tprev.date_two + 1;

答案 1 :(得分:1)

一种方法是使用窗口功能:

select
  date_one,
  date_two,
  sum(x) over (order by date_one) grp
from (
    select
        t.*,
        case when 
        lag(date_two) over (order by date_one) + 1 =
            date_one then 0 else 1 end x
    from t
);

它使用分析函数lag从最后一行找到date_two,并检查它是否继续使用此行中的date_one(按date_one的递增顺序)。

工作原理:

lag(date_two) over (order by date_one)

在下面的解释中,当我说第一行,下一行,上一行或最后一行时,它基于date_one的增加顺序,结尾为空值

上面的产生为第一行产生NULL,因为在它之前没有行来获取date_two,而前一行的date_two用于后续行。

case when 
      lag(date_two) 
      over (order by date_one) + 1 = date_one then 0
     else 1 end

因为,滞后为第一行产生NULL(因为NULL = anything表达式总是最终计算为false),case的输出将为1.

对于更多的行,将进行类似的检查以在查询输出中生成新列x,当前一行的date_two不与此行的date_one连续时,该列的值为1.

最后,我们可以在x上进行增量求和,以找到所需的组值。请参阅下面的x值以了解:

SQL> with t (date_one,date_two) as (
  2     select to_date('01.02.1999','dd.mm.yyyy'),to_date('31.05.2003','dd.mm.yyyy') from dual union
 all
  3     select to_date('01.01.2004','dd.mm.yyyy'),to_date('01.01.2010','dd.mm.yyyy') from dual union
 all
  4     select to_date('02.01.2010','dd.mm.yyyy'),to_date('10.10.2011','dd.mm.yyyy') from dual union
 all
  5     select to_date('11.10.2011','dd.mm.yyyy'),null from dual
  6  )
  7  select
  8    date_one,
  9    date_two,
 10    x,
 11    sum(x) over (order by date_one) grp
 12  from (
 13     select
 14             t.*,
 15             case when
 16             lag(date_two) over (order by date_one) + 1 =
 17                     date_one then 0 else 1 end x
 18     from t
 19  );

DATE_ONE  DATE_TWO           X        GRP
--------- --------- ---------- ----------
01-FEB-99 31-MAY-03          1          1
01-JAN-04 01-JAN-10          1          2
02-JAN-10 10-OCT-11          0          2
11-OCT-11                    0          2

SQL>