如何 Dense_Rank() 重复的值集

How to Dense_Rank() Sets of Values that Repeat

我有一个 table T 如下所示:

T Table

EMPLID  CODE    DT
101     PPP     01-JAN-15
101     PPP     02-JAN-15
101     PPP     03-JAN-15
101     OOO     04-JAN-15
101     OOO     05-JAN-15
101     PPP     06-JAN-15
101     PPP     07-JAN-15
101     PPP     08-JAN-15
101     PPP     09-JAN-15

我想要的是如下结果:

EMPLID  CODE    RNK   DT
101     PPP     1     01-JAN-15
101     PPP     1     02-JAN-15
101     PPP     1     03-JAN-15
101     OOO     2     04-JAN-15
101     OOO     2     05-JAN-15
101     PPP     3     06-JAN-15
101     PPP     3     07-JAN-15
101     PPP     3     08-JAN-15
101     PPP     3     09-JAN-15

但我似乎只得到如下结果:

SELECT EMPLID, CODE, DENSE_RANK() OVER(ORDER BY CODE) AS RNK, DT 
FROM T;


EMPLID  CODE    RNK   DT
101     OOO     1     05-JAN-15
101     OOO     1     04-JAN-15
101     PPP     2     03-JAN-15
101     PPP     2     08-JAN-15
101     PPP     2     09-JAN-15
101     PPP     2     06-JAN-15
101     PPP     2     07-JAN-15
101     PPP     2     02-JAN-15
101     PPP     2     01-JAN-15

由于 PPP 值在 OOO 值之后重复,但在以后的日期,我不确定如何 group/order 它以便我得到 RNK将第二组 PPP 值视为第三组的字段。

下面是 table 的代码,可以让这更容易一些:

WITH
T AS(
SELECT '101' AS EMPLID, 'PPP' AS CODE, '01-JAN-15' AS DT FROM DUAL
UNION ALL
SELECT '101', 'PPP', '02-JAN-15' FROM DUAL
UNION ALL
SELECT '101', 'PPP', '03-JAN-15' FROM DUAL
UNION ALL
SELECT '101', 'OOO', '04-JAN-15' FROM DUAL
UNION ALL
SELECT '101', 'OOO', '05-JAN-15' FROM DUAL
UNION ALL
SELECT '101', 'PPP', '06-JAN-15' FROM DUAL
UNION ALL
SELECT '101', 'PPP', '07-JAN-15' FROM DUAL
UNION ALL
SELECT '101', 'PPP', '08-JAN-15' FROM DUAL
UNION ALL
SELECT '101', 'PPP', '09-JAN-15' FROM DUAL
)
SELECT * 
FROM T;

我认为您需要两遍:首先找到代码更改的所有行,然后在此基础上构建一个组。

select emplid, code, sum(change) over (order by dt) as rnk, dt 
from
(
  select 
    emplid,
    code,
    case when lag(code) over (order by dt) = code then 0 else 1 end as change,
    dt
  from t
  order by dt
);

如果我没理解错的话,您想按 dt 对结果进行排序。您可以为每个更改的行设置标志,然后将标志加到该行,这将得到与 DENSE_RANK:

相同的结果
SELECT 
    sel2.emplid,
    sel2.code, 
    SUM (sel2.flg) OVER (ORDER BY sel2.dt ROWS BETWEEN UNBOUNDED PRECEDING AND 0 PRECEDING) rnk,
    sel2.dt
FROM
  ( SELECT
        sel1.emplid,
        sel1.code,
        CASE WHEN sel1.code = sel1.code_lag THEN 0 ELSE 1 END flg,
        sel1.dt
    FROM     
      ( SELECT emplid, code, dt, LAG(code,1,'XXX') OVER (ORDER BY dt) code_lag
        FROM T 
      ) sel1
  ) sel2
ORDER BY dt;

您唯一需要注意的是,无论天气如何,最后的结果都将被视为单独的排名。

也可以递归求解:

with s (u, s, a, n) as (
  select emplid, code, 1, dt from t where dt = date '2015-01-01'
  union all select emplid, code, a+decode(code, s, 0, 1), dt from t join s on dt=n+1 ) 
select * from s

SQLFiddle