sql >> データベース >  >> RDS >> Oracle

OracleのRANK、DENSE_RANK、およびROW_NUMBER関数

    Oracle Analytic関数は、現在の行の計算を実行するために使用される行の範囲を決定するwindowと呼ばれる行のグループに基づいて集計値を計算します。最もよく使用される分析関数は次のとおりです。
    – RANK、DENSE_RANK、ROW_NUMBER
    –LAGとLEAD
    –FIRST_VALUEとLAST_VALUE

    RANK、DENSE_RANK、ROW_NUMBERの分析関数について説明します。これらは本質的に非常に似ているため、要件に基づいて使用する必要があります。また、それらの違いについても説明します。

    一般的な構文は次のとおりです

    analytic_function([ arguments ]) OVER ([ query_partition_clause ] [ order_by_clause  ])
    

    OracleのROW_NUMBER関数

    ROW_NUMBER order_by_clauseで指定された行の順序付けられたシーケンスで、同じウィンドウの各行に一意の番号を割り当てます。

    まずサンプルデータを作成しましょう

    CREATE TABLE "DEPT"
    ( "DEPTNO" NUMBER(2,0),
    "DNAME" VARCHAR2(14),
    "LOC" VARCHAR2(13),
    CONSTRAINT "PK_DEPT" PRIMARY KEY ("DEPTNO")
    )
    
    CREATE TABLE "EMP"
    ( "EMPNO" NUMBER(4,0),
    "ENAME" VARCHAR2(10),
    "JOB" VARCHAR2(9),
    "MGR" NUMBER(4,0),
    "HIREDATE" DATE,
    "SAL" NUMBER(7,2),
    "COMM" NUMBER(7,2),
    "DEPTNO" NUMBER(2,0),
    CONSTRAINT "PK_EMP" PRIMARY KEY ("EMPNO"),
    CONSTRAINT "FK_DEPTNO" FOREIGN KEY ("DEPTNO")
    REFERENCES "DEPT" ("DEPTNO") ENABLE
    );
    
    SQL> desc emp
    Name Null? Type
    ---- ---- -----
    EMPNO NOT NULL NUMBER(4)
    ENAME VARCHAR2(10)
    JOB VARCHAR2(9)
    MGR NUMBER(4)
    HIREDATE DATE
    SAL NUMBER(7,2)
    COMM NUMBER(7,2)
    DEPTNO NUMBER(2)
    
    SQL> desc dept
    Name Null? Type
    ---- ----- ----
    DEPTNO NOT NULL NUMBER(2)
    DNAME VARCHAR2(14)
    LOC VARCHAR2(13)
    
    
    insert into DEPT values(10, 'ACCOUNTING', 'NEW YORK');
    insert into dept values(20, 'RESEARCH', 'DALLAS');
    insert into dept values(30, 'RESEARCH', 'DELHI');
    insert into dept values(40, 'RESEARCH', 'MUMBAI');
    commit;
    
    insert into emp values( 7839, 'Clark', 'MANAGER', 7839, to_date('9-6-2008','dd-mm-yyyy'), 28573, null, 10 );
    insert into emp values( 7782, 'Clara', 'MANAGER', 7839, to_date('9-6-2008','dd-mm-yyyy'), 0, null, 10 );
    insert into emp values( 7934, 'Blake', 'MANAGER', 7839, to_date('1-5-2007','dd-mm-yyyy'), 0, null, 10 );
    insert into emp values( 7788, 'Scott', 'ANALYST', 7788, to_date('9-6-2012','dd-mm-yyyy'), 30000, null, 20 );
    insert into emp values( 7902, 'Bill', 'ANALYST', 7832, to_date('9-6-2012','dd-mm-yyyy'), 30000, null, 20 );
    insert into emp values( 7876, 'TPM', 'ANALYST', 7566, to_date('9-6-2017','dd-mm-yyyy'), 11000, null, 20 );
    insert into emp values( 7369, 'TPM1', 'ANALYST', 7566, to_date('9-6-2017','dd-mm-yyyy'), 8000, null, 20 );
    
    insert into emp values( 7698, 'A1', 'ANALYST', 7788, to_date('9-6-2017','dd-mm-yyyy'), 28500, null, 30 );
    insert into emp values( 7499, 'A2', 'ANALYST', 7698, to_date('9-7-2017','dd-mm-yyyy'), 16000, null, 30 );
    insert into emp values( 7844, 'A3', 'ANALYST', 7698, to_date('9-7-2017','dd-mm-yyyy'), 15000, null, 30 );
    insert into emp values( 7654, 'A4', 'ANALYST', 7698, to_date('9-7-2017','dd-mm-yyyy'), 12500, null, 30 );
    insert into emp values( 7521, 'A5', 'ANALYST', 7698, to_date('9-7-2017','dd-mm-yyyy'), 12500, null, 30 );
    insert into emp values( 7900, 'A6', 'ANALYST', 77698, to_date('9-7-2017','dd-mm-yyyy'), 0, null, 30 );
    commit;
    SQL> desc emp
     Name                                      Null?    Type
     ----------------------------------------- -------- ----------------------------
     EMPNO                                     NOT NULL NUMBER(4)
     ENAME                                              VARCHAR2(10)
     JOB                                                VARCHAR2(9)
     MGR                                                NUMBER(4)
     HIREDATE                                           DATE
     SAL                                                NUMBER(7,2)
     COMM                                               NUMBER(7,2)
     DEPTNO                                             NUMBER(2)
    
    SQL> select deptno ,count(*) from emp group by deptno;
    
        DEPTNO   COUNT(*)
    ---------- ----------
            30          6
            20          4
            10          3
    
    SQL> select
    deptno, ename, sal,
     row_number() over (partition by deptno order by sal) "row_number"
    from
    emp;
    
    DEPTNO        ENAME       SAL    row_number
    ---------- ---------- ---------- ---------- 
    10          CLARK          0        1 
    10          MILLER         0        2
    10          allen          28573    3
    20          SMITH          8000     1
    20          ADAMS          11000    2
    20          SCOTT          30000    3
    20          FORD           30000    4
    30          JAMES          9500     1
    30          MARTIN         12500    2
    30          WARD           12500    3
    30          TURNER         15000    4
    30          ALLEN          16000    5
    30          BLAKE          28500    6 
    
    13 rows selected.

    OracleのRANK関数

    ランク ROW_NUMBERとほぼ同じですが、同じウィンドウ内で、order by句が指定されている値が等しい行は同じランクを受け取りますが、次の行はROW_NUMBERに従ってRANKを受け取ります。

    SQL> select
    deptno, ename, sal,
     rank() over (partition by deptno order by sal) "RANK"
    from
    emp;
    
    DEPTNO        ENAME       SAL    RANK
    ---------- ---------- ---------- ---------- 
    10          CLARK          0        1 
    10          MILLER         0        2
    10          allen          28573    3
    20          SMITH          8000     1
    20          ADAMS          11000    2
    20          SCOTT          30000    3
    20          FORD           30000    3
    30          JAMES          9500     1
    30          MARTIN         12500    2
    30          WARD           12500    2
    30          TURNER         15000    4
    30          ALLEN          16000    5
    30          BLAKE          28500    6 
    
    13 rows selected.
    

    OracleのDense_rank関数

    DENSE_RANK RANKとほぼ同じですが、1つ以上の値が同じである場合、行間にギャップは残りません。次の例のように、同じグループのWARDの横にあるTURNERはDENSE_RANK3を受け取ります。

    SQL> select
    deptno, ename, sal,
     dense_rank() over (partition by deptno order by sal) "DENSE_RANK"
    from
    emp;
    
    DEPTNO        ENAME       SAL    DENSE_RANK
    ---------- ---------- ---------- ---------- 
    10          CLARK          0        1 
    10          MILLER         0        2
    10          allen          28573    3
    20          SMITH          8000     1
    20          ADAMS          11000    2
    20          SCOTT          30000    3
    20          FORD           30000    3
    30          JAMES          9500     1
    30          MARTIN         12500    2
    30          WARD           12500    2
    30          TURNER         15000    3
    30          ALLEN          16000    4
    30          BLAKE          28500    5 
    
    13 rows selected.

    3つすべてを1つのクエリに入れることもできます

    select
      deptno, ename, sal,
      row_number() over (partition by deptno order by sal) "row_number",
         rank() over (partition by deptno order by sal) "rank",
              dense_rank() over (partition by deptno order by sal) "dense_rank"
            from
              emp;
    
        DEPTNO ENAME             SAL row_number       rank dense_rank
    ---------- ---------- ---------- ---------- ---------- ----------
            10 CLARK               0          1          1          1
            10 MILLER              0          2          1          1
            10 allen           28573          3          3          2
            20 SMITH            8000          1          1          1
            20 ADAMS           11000          2          2          2
            20 SCOTT           30000          3          3          3
            20 FORD            30000          4          3          3
            30 JAMES            9500          1          1          1
            30 MARTIN          12500          2          2          2
            30 WARD            12500          3          2          2
            30 TURNER          15000          4          4          3
            30 ALLEN           16000          5          5          4
            30 BLAKE           28500          6          6          5
    
    13 rows selected.
    >

    重複する行を削除するには、Row_number関数とRANK関数を使用できます

    delete from t
     where rowid IN ( select rid
                        from (select rowid rid, 
                                     row_number() over (partition by 
                             column_name
                                       order by rowid) rn
                                from t)
                       where rn <> 1);
    

    これらの関数は、上位Nおよび下位Nのクエリに非常に役立ちます。

    以下のSQLを使用して、各部門の最高給与を見つけることができます

    SQL> select * (select
    deptno, ename, sal,
     row_number() over (partition by deptno order by sal) "row_number"
    from
    emp ) where row_number=1;

    Oracle Analytic関数のようなRANK、DENSE_RANK、ROW_NUMBERの説明と、クエリでデータを分析する方法について説明していただければ幸いです。クエリでこれらの関数を使用するときは、細心の注意を払う必要があります。そうしないと、結果が異なります。

    関連記事

    OracleのLEAD関数
    Oracleの分析関数
    Oracleインタビューの質問
    Oracle集合演算子
    OracleSqlチュートリアル
    高密度ランクのOracleドキュメント


    1. SQLclで構文の強調表示を構成する方法

    2. pyodbcはデータベースに接続できません

    3. PowerShellをSalesforce.comに接続する

    4. WEEKDAY()の例– MySQL