Home » SQL & PL/SQL » SQL & PL/SQL » Rank without analytical function (11.2.0.3)
Rank without analytical function [message #606137] Mon, 20 January 2014 05:38 Go to next message
rishwinger
Messages: 132
Registered: November 2011
Senior Member
Hello Experts,

Consider SCOTT.EMP Table

SQL> SELECT deptno,
  hiredate,
  row_number() over(partition BY deptno order by hiredate) AS rank
FROM emp;

    DEPTNO HIREDATE        RANK
---------- --------- ----------
        10 09-JUN-81          1
        10 17-NOV-81          2
        10 23-JAN-82          3
        20 17-DEC-80          1
        20 02-APR-81          2
        20 03-DEC-81          3
        20 19-APR-87          4
        20 23-MAY-87          5
        30 20-FEB-81          1
        30 22-FEB-81          2
        30 01-MAY-81          3
        30 08-SEP-81          4
        30 28-SEP-81          5
        30 03-DEC-81          6

14 rows selected.


I need above output without using analytical function, Please advise

Regards
Re: Rank without analytical function [message #606138 is a reply to message #606137] Mon, 20 January 2014 05:45 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
You need to tell us why you're trying to avoid using the tool that's specifically designed for this job, since the reasons will probably affect what subsitutes are acceptable.
I can't think of a pure sql alternative off the top of my head.
Re: Rank without analytical function [message #606139 is a reply to message #606138] Mon, 20 January 2014 05:48 Go to previous messageGo to next message
rishwinger
Messages: 132
Registered: November 2011
Senior Member

Well my app dev is having trouble using partition in JPA query,

guys thx anyways i got it

SQL> SELECT d1.deptno,
  2    d1.hiredate,
  3    row_number() over(partition BY deptno order by hiredate DESC) AS rank
  4    (SELECT COUNT(*)+1
  5    FROM emp d2
  6    WHERE d1.deptno=d2.deptno
  7    AND d1.hiredate<d2.hiredate
  8    ) as test
  9  FROM emp d1;

    DEPTNO HIREDATE        RANK       TEST
---------- --------- ---------- ----------
        10 23-JAN-82          1          1
        10 17-NOV-81          2          2
        10 09-JUN-81          3          3
        20 23-MAY-87          1          1
        20 19-APR-87          2          2
        20 03-DEC-81          3          3
        20 02-APR-81          4          4
        20 17-DEC-80          5          5
        30 03-DEC-81          1          1
        30 28-SEP-81          2          2
        30 08-SEP-81          3          3

    DEPTNO HIREDATE        RANK       TEST
---------- --------- ---------- ----------
        30 01-MAY-81          4          4
        30 22-FEB-81          5          5
        30 20-FEB-81          6          6

14 rows selected.

[Updated on: Mon, 20 January 2014 05:50]

Report message to a moderator

Re: Rank without analytical function [message #606140 is a reply to message #606139] Mon, 20 January 2014 05:51 Go to previous messageGo to next message
Littlefoot
Messages: 21808
Registered: June 2005
Location: Croatia, Europe
Senior Member
Account Moderator
How do you call
row_number() over(partition BY deptno order by hiredate DESC)
regarding your question which says
Quote:
I need above output without using analytical function
Re: Rank without analytical function [message #606143 is a reply to message #606139] Mon, 20 January 2014 06:04 Go to previous messageGo to next message
Lalit Kumar B
Messages: 3174
Registered: May 2013
Location: World Wide on the Web
Senior Member
rishwinger wrote on Mon, 20 January 2014 17:18

Well my app dev is having trouble using partition in JPA query,

guys thx anyways i got it

SQL> SELECT d1.deptno,
  2    d1.hiredate,
  3    row_number() over(partition BY deptno order by hiredate DESC) AS rank
  4    (SELECT COUNT(*)+1
  5    FROM emp d2
  6    WHERE d1.deptno=d2.deptno
  7    AND d1.hiredate<d2.hiredate
  8    ) as test
  9  FROM emp d1;


And more trouble is round the corner. You are accessing the tables twice unnecessarily. So on what cost you want to avoid analytic and use this performance degrading query?
Re: Rank without analytical function [message #606144 is a reply to message #606143] Mon, 20 January 2014 06:06 Go to previous messageGo to next message
Littlefoot
Messages: 21808
Registered: June 2005
Location: Croatia, Europe
Senior Member
Account Moderator
Right. Sorry, my mouth is faster than my mind once again (maybe I should turn that "mind" on, instead of having it on standby).
Re: Rank without analytical function [message #606146 is a reply to message #606144] Mon, 20 January 2014 06:12 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
Ok that'll work, but as Lalit says, for large data sets it'll be horribly slow, so you may want to work out why there's an issue with using analytics and fix it.
Re: Rank without analytical function [message #606147 is a reply to message #606139] Mon, 20 January 2014 06:13 Go to previous message
Solomon Yakobson
Messages: 3273
Registered: January 2010
Location: Connecticut, USA
Senior Member
rishwinger wrote on Mon, 20 January 2014 06:48

guys thx anyways i got it


It is not clear how you want to rank equal values. Your solution doesn't rank rows same way as ROW_NUMBER numbers them. It mimics RANK, not ROW_NUMBER:

SQL> update emp
  2    set hiredate = date '2013-01-01'
  3    where deptno = 20
  4      and rownum <= 2
  5  /

2 rows updated.

SQL> update emp
  2    set hiredate = date '2014-01-01'
  3    where deptno = 20
  4      and hiredate != date '2013-01-01'
  5      and rownum <= 2
  6  /

2 rows updated.

SQL> SELECT  d1.deptno,
  2          d1.hiredate,
  3          row_number() over(partition BY deptno order by hiredate DESC) AS your_rank,
  4          rank() over(partition BY deptno order by hiredate DESC) AS actual_rank,
  5          (
  6           SELECT  COUNT(*) + 1
  7             FROM  emp d2
  8             WHERE d1.deptno=d2.deptno
  9             AND d1.hiredate<d2.hiredate
 10          ) as test
 11    FROM  emp d1
 12  /

    DEPTNO HIREDATE   YOUR_RANK ACTUAL_RANK       TEST
---------- --------- ---------- ----------- ----------
        10 23-JAN-82          1           1          1
        10 17-NOV-81          2           2          2
        10 09-JUN-81          3           3          3
        20 01-JAN-14          1           1          1
        20 01-JAN-14          2           1          1
        20 01-JAN-13          3           3          3
        20 01-JAN-13          4           3          3
        20 03-DEC-81          5           5          5
        30 03-DEC-81          1           1          1
        30 28-SEP-81          2           2          2
        30 08-SEP-81          3           3          3

    DEPTNO HIREDATE   YOUR_RANK ACTUAL_RANK       TEST
---------- --------- ---------- ----------- ----------
        30 01-MAY-81          4           4          4
        30 22-FEB-81          5           5          5
        30 20-FEB-81          6           6          6

14 rows selected.

SQL> rollback
  2  /

Rollback complete.

SQL>


Add ROWID, if you want to mimic ROW_NUMBER:

SQL> update emp
  2    set hiredate = date '2013-01-01'
  3    where deptno = 20
  4      and rownum <= 2
  5  /

2 rows updated.

SQL> update emp
  2    set hiredate = date '2014-01-01'
  3    where deptno = 20
  4      and hiredate != date '2013-01-01'
  5      and rownum <= 2
  6  /

2 rows updated.

SQL> SELECT  d1.deptno,
  2          d1.hiredate,
  3          row_number() over(partition BY deptno order by hiredate DESC) AS your_rank,
  4          rank() over(partition BY deptno order by hiredate DESC) AS actual_rank,
  5          (
  6           SELECT  COUNT(*) + 1
  7             FROM  emp d2
  8             WHERE d1.deptno = d2.deptno
  9               AND d1.hiredate < d2.hiredate
 10              OR (
 11                      d1.hiredate = d2.hiredate
 12                  AND
 13                      d1.rowid < d2.rowid
 14                 )
 15          ) as test
 16    FROM  emp d1
 17    order by d1.deptno,
 18             test
 19  /

    DEPTNO HIREDATE   YOUR_RANK ACTUAL_RANK       TEST
---------- --------- ---------- ----------- ----------
        10 23-JAN-82          1           1          1
        10 17-NOV-81          2           2          2
        10 09-JUN-81          3           3          3
        20 01-JAN-14          2           1          1
        20 01-JAN-14          1           1          2
        20 01-JAN-13          3           3          3
        20 01-JAN-13          4           3          4
        20 03-DEC-81          5           5          5
        30 03-DEC-81          1           1          2
        30 28-SEP-81          2           2          2
        30 08-SEP-81          3           3          3

    DEPTNO HIREDATE   YOUR_RANK ACTUAL_RANK       TEST
---------- --------- ---------- ----------- ----------
        30 01-MAY-81          4           4          4
        30 22-FEB-81          5           5          5
        30 20-FEB-81          6           6          6

14 rows selected.

SQL> rollback
  2  /

Rollback complete.

SQL>


SY.
Previous Topic: SQL query
Next Topic: The INTO clause of a SELECT statement of PL/SQL block
Goto Forum:
  


Current Time: Thu Apr 25 07:18:42 CDT 2024