Oracle Analytic函数 - 重置窗口子句

时间:2013-07-24 02:53:56

标签: sql oracle analytic-functions

我有以下数据集。

create table t1 (
  dept number,
  date1 date
);

Table created.

insert into t1 values (100, '01-jan-2013');
insert into t1 values (100, '02-jan-2013');
insert into t1 values (200, '03-jan-2013');
insert into t1 values (100, '04-jan-2013');
commit;

我的目标是创建一个排名列,每次更改部门时都会重置。我可以用于“分区依据”子句的最接近的列是dept,但这不会给我想要的结果。

SQL> select * from t1;

      DEPT DATE1
---------- ---------
       100 01-JAN-13
       100 02-JAN-13
       200 03-JAN-13
       100 04-JAN-13

select dept,  
       date1,
       rank () Over (partition by dept order by date1) rnk
from t1
order by date1;

      DEPT DATE1            RNK
---------- --------- ----------
       100 01-JAN-13          1
       100 02-JAN-13          2
       200 03-JAN-13          1
       100 04-JAN-13          3

所需的输出如下。最后一个rnk = 1是因为Jan-04记录是变更后的第一个记录。

      DEPT DATE1            RNK
---------- --------- ----------
       100 01-JAN-13          1
       100 02-JAN-13          2
       200 03-JAN-13          1
       100 04-JAN-13          1  <<<----------

任何指针?

3 个答案:

答案 0 :(得分:4)

这有点复杂。不要使用rank()之类的内容,而是使用lag()查看更改内容的时间。然后做一个累积的旗帜。

select dept, date1,
       CASE WHEN StartFlag = 0 THEN 1
            ELSE 1+StartFlag+NVL(lag(StartFlag) over (order by date1),0)
       END as rnk
from (select t1.*,
             (case when dept = lag(dept) over (order by date1)
                   then 1
                   else 0
              end) as StartFlag
      from t1
     ) t1
order by date1;

Here是SQLFiddle。

编辑:

这是戈登编辑我自己的答案。哎呀。原始查询是90%的方式。它确定了,其中数字应该增加,但没有分配组内的数字。我会使用另一个row_number()级别执行此操作,如:

select dept, date1,
       row_number() over (partition by dept, grp order by date1) as rnk
from (select dept, date1, startflag,
             sum(StartFlag) over (partition by dept order by date1) as grp
      from (select t1.*,
                   (case when dept = lag(dept) over (order by date1)
                         then 0
                         else 1
                    end) as StartFlag
            from t1
           ) t1
     ) t1
order by date1;

因此,总体思路如下。首先使用lag()来确定组的开始位置(即,从一个日期到下一个日期的部门更改)。然后,通过累积总和为这些分配“组ID”。这些是要枚举的记录。最后一步是使用row_number()枚举它们。

答案 1 :(得分:2)

这可能是model子句的情况,但不幸的是,与Gordon的查询相比,它在大量行上表现不佳。

select dept, date1, rank from t1
model 
  dimension by ( row_number() over(order by date1) as rn )
  measures( 1 as rank, dept, date1 ) 
  rules ( 
    rank[1] = 1,
    rank[rn > 1] = 
    case dept[cv()] 
      when dept[cv()-1] then rank[cv()-1] + 1 
      else 1
     end
  )

http://www.sqlfiddle.com/#!4/fc339/132

答案 2 :(得分:0)

方法是:

  1. 使用“行号”和“已更改”标记标记每一行
  2. 计算最终'rnk'作为'行号'与最后一个'行号'之间的差异,该行号对应于'已更改'行。
  3. 这与戈登的答案类似,但是使用我觉得更容易阅读的CTE写的。

    with cte as (
        select dept, date1,
            row_number() over (order by date1) as row,
            case when dept = (lag(dept) over (order by date1)) then 0 else 1 end as changed
        from t1
    )
    select dept, date1, 
        row - max(case when changed = 1 then row else 1 end) over (order by date1) + 1 as rnk
    from cte
    order by date1