Dense Rank with order by Dense Rank with order by oracle oracle

Dense Rank with order by


Try LAG

WITH flagged AS (      SELECT *,       CASE WHEN LAG(RCD) OVER(PARTITION BY EMPLID ORDER BY EFFDT) = RCD               AND LAG(COMPANY) OVER(PARTITION BY EMPLID ORDER BY EFFDT) = COMPANY THEN 0 ELSE 1 END strtFlag    FROM tbl    )SELECT EMPLID, RCD, COMPANY, EFFDT, SALARY, SUM(strtFlag) OVER(PARTITION BY EMPLID ORDER BY EFFDT) COUNTERFROM flagged

alternatively, with DENSE_RANK() of group

WITH grps AS (      SELECT *,       ROW_NUMBER() OVER(PARTITION BY EMPLID ORDER BY EFFDT) -      ROW_NUMBER() OVER(PARTITION BY EMPLID, RCD, COMPANY ORDER BY EFFDT) grp    FROM tbl    )SELECT EMPLID, RCD, COMPANY, EFFDT, SALARY  , DENSE_RANK() OVER(PARTITION BY EMPLID ORDER BY grp) COUNTERFROM grps

Anyway looks like two steps are needed to get dense numbering.


This should work - with the clarification that a combination of rcd and company should keep the same "counter" even if it appears in non-consecutive periods. I added to more rows to the test data to make sure I get the correct result.

Like Serg's solutions (which answer a different question), the solution does one pass over the base data, and then a second pass over the results of the first pass (all in memory, so it should be relatively fast). There's no way around that - this requires two different analytic functions where one depends on the results of the other, and nested analytic functions are not allowed. (This part of the answer addresses a comment by the OP to the Answer by Serg.)

with     test_data ( emplid, rcd, company, effdt, salary ) as (       select 100, 0, 'xyz', to_date('1/1/2000' , 'mm/dd/yyyy'), 1000 from dual union all       select 100, 0, 'xyz', to_date('1/15/2000', 'mm/dd/yyyy'), 1100 from dual union all       select 100, 0, 'xyz', to_date('1/31/2000', 'mm/dd/yyyy'), 1200 from dual union all       select 100, 0, 'ggg', to_date('2/15/2000', 'mm/dd/yyyy'), 1500 from dual union all       select 100, 1, 'abc', to_date('3/1/2000' , 'mm/dd/yyyy'), 2000 from dual union all       select 100, 1, 'abc', to_date('4/1/2000' , 'mm/dd/yyyy'), 2100 from dual union all       select 100, 0, 'xyz', to_date('5/1/2000' , 'mm/dd/yyyy'), 2200 from dual union all       select 100, 1, 'ggg', to_date('8/15/2000', 'mm/dd/yyyy'), 2300 from dual     )-- end of test data; the actual solution (SQL query) begins below this lineselect emplid, rcd, company, effdt, salary,       dense_rank() over (partition by emplid order by min_dt) as counterfrom ( select emplid, rcd, company, effdt, salary,               min(effdt) over (partition by emplid, rcd, company) as min_dt       from   test_data )order by effdt                --   ORDER BY is optional;    EMPLID        RCD COM EFFDT                   SALARY    COUNTER---------- ---------- --- ------------------- ---------- ----------       100          0 xyz 2000-01-01 00:00:00       1000          1       100          0 xyz 2000-01-15 00:00:00       1100          1       100          0 xyz 2000-01-31 00:00:00       1200          1       100          0 ggg 2000-02-15 00:00:00       1500          2       100          1 abc 2000-03-01 00:00:00       2000          3       100          1 abc 2000-04-01 00:00:00       2100          3       100          0 xyz 2000-05-01 00:00:00       2200          1       100          1 ggg 2000-08-15 00:00:00       2300          4 8 rows selected


I think you're looking for:

SELECT EMPLID,RCD,COMPANY,EFFDT,    DENSE_RANK() over (order by EMPLID , RCD , COMPANY) AS COUNTERFROM (select * from ASSIGNMENT order by EFFDT);

or

SELECT EMPLID,RCD,COMPANY,EFFDT,    DENSE_RANK() over (order by EMPLID , RCD , COMPANY) AS COUNTERFROM (select * from ASSIGNMENT order by EMPLID , RCD , COMPANY, EFFDT);