我有以下数据集。
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;
我的目标是创建一个等级列,每次部门更改时都会重置。对于"partitionby"子句,我可以使用的最接近的列是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是因为2004年1月的记录是更改后的第一个记录。
DEPT DATE1 RNK
---------- --------- ----------
100 01-JAN-13 1
100 02-JAN-13 2
200 03-JAN-13 1
100 04-JAN-13 1 <<<----------
有指针吗?
这有点复杂。不要使用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;
这是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()
枚举它们。
这可能是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
方法是:
- 用"行号"one_answers"已更改"标志标记每一行
- 计算最后的"rnk",作为"行号"和对应于"更改"行的前一个最大"行号"之间的差值
这与Gordon的答案相似,但使用的是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