简体   繁体   中英

how can i write rank sql in oracle like mysql

my sql segment in mysql:

SELECT t.*,@r1:=@r1+1 r1,@r:=IF(@v=score OR(@v IS NULL AND score IS NULL),@r,@r1) rank,@v:=score v1 
FROM(SELECT @r :=0) a,(SELECT @r1 :=0) b,(SELECT @v:=NULL) v,(SELECT id,score FROM exam_inst 
WHERE eid = '1161918326813872128' AND type = 2 GROUP BY dealer 
ORDER BY i_level DESC,create_date DESC) t ORDER BY score DESC

i want to write same query sql in oracle,how can i do it?

table:

A     B
c1    a
c1    b
c1    a
c2    a
c2    a
c2    b

query result:

A     B    R
c1    a    1
c1    b    2
c1    a    3
c2    a    1
c2    a    1
c2    b    3

Use the RANK analytic function:

SELECT t.*,
       RANK() OVER ( PARTITION BY a ORDER BY b ) AS r
FROM   table_name t;

or your sample data:

CREATE TABLE table_name ( a, b ) AS
SELECT 'c1', 'a' FROM DUAL UNION ALL
SELECT 'c1', 'b' FROM DUAL UNION ALL
SELECT 'c1', 'a' FROM DUAL UNION ALL
SELECT 'c2', 'a' FROM DUAL UNION ALL
SELECT 'c2', 'a' FROM DUAL UNION ALL
SELECT 'c2', 'b' FROM DUAL;

This outputs:

\nA | B | R\n:- |  :- |  -: \nc1 |  a |  1 \nc1 |  a |  1 \nc1 |  b | 3 \nc2 |  a |  1 \nc2 |  a |  1 \nc2 |  b | 3 \n

db<>fiddle here


Update

I just want to compare adjacent rows,i do not care about how many 'a'

Rows in SQL are unordered; so you will need another column to store the order of the rows:

CREATE TABLE table_name ( a, b, c ) AS
SELECT 'c1', 'a', 1 FROM DUAL UNION ALL
SELECT 'c1', 'b', 2 FROM DUAL UNION ALL
SELECT 'c1', 'a', 3 FROM DUAL UNION ALL
SELECT 'c2', 'a', 1 FROM DUAL UNION ALL
SELECT 'c2', 'a', 2 FROM DUAL UNION ALL
SELECT 'c2', 'b', 3 FROM DUAL;

This will find the dense rank of the rows:

SELECT a,
       b,
       c,
       SUM( has_changed ) OVER ( PARTITION BY a ORDER BY c ) AS r
FROM   (
  SELECT t.*,
         CASE
         WHEN b = LAG( b ) OVER ( PARTITION BY a ORDER BY c )
         THEN 0
         ELSE 1
         END AS has_changed
  FROM   table_name t
)
ORDER BY a, c;

Which outputs:

\nA | B | C |  R\n:- |  :- |  -: |  -: \nc1 |  a |  1 |  1 \nc1 |  b | 2 |  2 \nc1 |  a |  3 |  3 \nc2 |  a |  1 |  1 \nc2 |  a |  2 |  1 \nc2 |  b | 3 |  2 \n

If you want the (sparse) rank then you can take the previous output and apply the RANK analytic function to it:

SELECT a,
       b,
       c,
       RANK() OVER ( PARTITION BY a ORDER BY r ) AS r
FROM   (
  SELECT a,
         b,
         c,
         SUM( has_changed ) OVER ( PARTITION BY a ORDER BY c ) AS r
  FROM   (
    SELECT t.*,
           CASE
           WHEN b = LAG( b ) OVER ( PARTITION BY a ORDER BY c )
           THEN 0
           ELSE 1
           END AS has_changed
    FROM   table_name t
  )
)
ORDER BY a, c;

Which outputs:

\nA | B | C |  R\n:- |  :- |  -: |  -: \nc1 |  a |  1 |  1 \nc1 |  b | 2 |  2 \nc1 |  a |  3 |  3 \nc2 |  a |  1 |  1 \nc2 |  a |  2 |  1 \nc2 |  b | 3 |  3 \n

You can also use MATCH_RECOGNIZE to compare sequential rows:

SELECT a,
       b,
       c,
       dense_rank,
       RANK() OVER( PARTITION BY a ORDER BY dense_rank ) AS sparse_rank
FROM   table_name
MATCH_RECOGNIZE (
   PARTITION BY a
   ORDER BY     c
   MEASURES     MATCH_NUMBER() AS dense_rank
   ALL ROWS PER MATCH
   PATTERN      (FIRST_ROW EQUAL_ROWS*)
   DEFINE       EQUAL_ROWS AS EQUAL_ROWS.b = PREV(EQUAL_ROWS.b)
)

Which outputs:

\nA | B | C |  DENSE_RANK |  SPARSE_RANK \n:- |  :- |  -: |  ---------: |  ----------: \nc1 |  a |  1 |  1 |  1 \nc1 |  b | 2 |  2 |  2 \nc1 |  a |  3 |  3 |  3 \nc2 |  a |  1 |  1 |  1 \nc2 |  a |  2 |  1 |  1 \nc2 |  b | 3 |  2 |  3 \n

db<>fiddle here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM