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

oracleで分析関数を使用する方法(キーワードによるパーティションオーバー)

    この投稿はOracleSQLチュートリアルの一部であり、Oracleの分析関数(パーティションごと)について、例と詳細な説明を使用して説明します。

    avg、sum、countなどのOracleAggregate関数についてはすでに学習しました。例を見てみましょう

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

    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, 'Allen', 'MANAGER', 7839, to_date('17-11-1981','dd-mm-yyyy'), 20, null, 10 );
    insert into emp values( 7782, 'CLARK', 'MANAGER', 7839, to_date('9-06-1981','dd-mm-yyyy'), 0, null, 10 );
    insert into emp values( 7934, 'MILLER', 'MANAGER', 7839, to_date('23-01-1982','dd-mm-yyyy'), 0, null, 10 );
    insert into emp values( 7788, 'SMITH', 'ANALYST', 7788, to_date('17-12-1980','dd-mm-yyyy'), 800, null, 20 );
    insert into emp values( 7902, 'ADAM, 'ANALYST', 7832, to_date('23-05-1987','dd-mm-yyyy'), 1100, null, 20 );
    insert into emp values( 7876, 'FORD', 'ANALYST', 7566, to_date('3-12-1981','dd-mm-yyyy'), 3000, null, 20 );
    insert into emp values( 7369, 'SCOTT', 'ANALYST', 7566, to_date('19-04-1987','dd-mm-yyyy'), 3000, null, 20 );
    insert into emp values( 7698, 'JAMES', 'ANALYST', 7788, to_date('03-12-1981','dd-mm-yyyy'), 950, null, 30 );
    insert into emp values( 7499, 'MARTIN', 'ANALYST', 7698, to_date('28-09-1981','dd-mm-yyyy'), 1250, null, 30 );
    insert into emp values( 7844, 'WARD', 'ANALYST', 7698, to_date('22-02-1981','dd-mm-yyyy'), 1250, null, 30 );
    insert into emp values( 7654, 'TURNER', 'ANALYST', 7698, to_date('08-09-1981','dd-mm-yyyy'), 1500, null, 30 );
    insert into emp values( 7521, 'ALLEN', 'ANALYST', 7698, to_date('20-02-1981','dd-mm-yyyy'), 1600, null, 30 );
    insert into emp values( 7900, 'BLAKE', 'ANALYST', 77698, to_date('01-05-1981','dd-mm-yyyy'), 2850, null, 30 );
    commit;
    
    

    ここで、集計関数の例を以下に示します

    select count(*) from EMP;
    ---------
    13
    
    select sum (bytes) from dba_segments where tablespace_name='TOOLS';
    -----
    100
    
    SQL> select deptno ,count(*) from emp group by deptno;
    
    DEPTNO COUNT(*)
    ---------- ----------
    30              6
    20              4
    10              3
    

    ここでは、各クエリの行数が減少していることがわかります。ここで、すべての行をcount(*)で返す必要がある場合はどうすればよいかという質問があります

    そのために、オラクルは一連の分析関数を提供しています。したがって、最後の問題を解決するために、次のように書くことができます

    select empno ,deptno , count(*) over (partition by deptno) from emp group by deptno;

    ここで、count(*)over(dept_noによるパーティション)は、カウント集計関数の分析バージョンです。集計関数によって異なる主な重要な作業は、分割による

    です。

    分析関数は、行のグループに基づいて集計値を計算します。これらは、グループごとに複数の行を返すという点で集計関数とは異なります。行のグループはウィンドウと呼ばれ、analytic_clauseによって定義されます。

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

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

    count(*) over (partition by deptno)
    
    avg(Sal) over (partition by deptno)
    

    各部分を見ていきましょう

    query_partition_clause
    行のグループを定義しました。以下のようになります

    deptnoによるパーティション:同じdeptnoの行のグループ
    または
    ():すべての行

    SQL> select empno ,deptno , count(*) over () from emp;

    [order_by_clause [windowing_clause]]

    この句は、パーティション内の行を並べ替える場合に使用されます。これは、分析関数で行の順序を考慮したい場合に特に便利です。

    例はrow_number関数です

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

    別の例は

    です
    SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE) running_sum from emp;

    Windowing_clause

    これは常にorderby句で使用され、グループ内の行のセットをより細かく制御できます

    Windowing句を使用すると、行ごとに、行のスライディングウィンドウが定義されます。ウィンドウは、現在の行の計算を実行するために使用される行の範囲を決定します。ウィンドウサイズは、物理的な行数または時間などの論理的な間隔に基づくことができます。

    order by句を使用し、windowing_clauseに何も指定されていない場合、windowing_clauseのデフォルト値を下回る値が使用されます
    UNBOUNDEDPRECEDINGとCURRENTROWの間のRANGEまたはRANGEUNBOUNDEDPRECEDING
    これは「パーティションは、計算で使用する必要がある行です」

    以下の例はこれを明確に示しています。これは部門の移動平均になります

    SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE) running_sum from emp;

    これで、windowing_clauseをさまざまな方法で定義できるようになりました
    最初に用語を理解しましょう

    ウィンドウを物理単位(行)で指定します。
    範囲 ウィンドウを論理オフセットとして指定します。 RANGEウィンドウ句は、数値または日付のデータ型の列または式を含むORDERBY句でのみ使用できます
    PRECEDING –現在の行より前の行を取得します。
    フォロー中 –現在の行の後に行を取得します。
    無制限 – PRECEDINGまたはFOLLOWINGと一緒に使用すると、すべての前後に戻ります。現在の行

    したがって、一般的には

    と定義されます。

    前に無制限の行 :現在のパーティションの現在の行と前の行は、計算で使用する必要がある行です

    SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE ROWS UNBOUNDED PRECEDING) running_sum from emp;

    範囲の制限のない前へ :現在のパーティションの現在の行と前の行は、計算で使用する必要のある行です。また、範囲が指定されているため、すべてが現在の行と等しい値を取ります。

    SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE RANGE UNBOUNDED PRECEDING) running_sum from emp;

    範囲と行の違いは、hire_dateがすべての場合で異なるため、表示されない場合があります。salを句ごとの順序として使用すると、違いがより明確になります。

    SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by sal RANGE UNBOUNDED PRECEDING) running_sum from emp;
    SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by sal ROWS UNBOUNDED PRECEDING) running_sum from emp;

    6行目で違いを確認できます

    RANGE value_expr PRECEDING :ウィンドウは、ORDER BY値が現在の行よりも小さい、または前の数値式行である行で始まり、処理中の現在の行で終わります。

    SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE RANGE 365 PRECEDING) running_sum from emp;

    ここでは、現在の行の採用日値より365日以内に採用日値が含まれるすべての行を取得します

    ROWS value_expr PRECEDING :ウィンドウは指定された行で始まり、処理中の現在の行で終わります

    SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE ROWS 2 PRECEDING) running_sum from emp;

    ここで、ウィンドウは現在の行の前の2行から始まります

    現在の行と次のvalue_exprの間の範囲 :ウィンドウは現在の行で始まり、ORDERBY値が数値式の行よりも小さいか次の行で終わります

    SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE ROWS between current row and 1 FOLLOWING) running_sum from emp;

    現在の行と次のvalue_exprの間の行 :ウィンドウは現在の行で始まり、現在の行の後の行で終わります

    SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE ROWS between current row and 1 FOLLOWING) running_sum from emp;

    無制限の先行と無制限の後続の間の範囲

    SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE RANGE BETWEEN UNBOUNDED PRECEDING and UNBOUNDED FOLLOWING
    ) running_sum from emp;

    value_exprPRECEDINGとvalue_exprFOLLOWINGの間の範囲

    SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE RANGE BETWEEN 365 PRECEDING and 365 FOLLOWING
    ) running_sum from emp; 2
    
    DEPTNO       ENAME      HIREDATE      SAL      RUNNING_SUM
    ---------- ---------- --------------- ---------- -----------
    10           CLARK       09-JUN-81      0          0
    10           ALLEN       17-NOV-81      0          0
    10           MILLER      23-JAN-82      0          0
    20           SMITH       17-DEC-80      800       3800
    20           FORD        03-DEC-81      3000      3800
    20           SCOTT       19-APR-87      3000      4100
    20           ADAMS       23-MAY-87      1100      4100
    30           ALLEN       20-FEB-81      1600      9400
    30           WARD        22-FEB-81      1250      9400
    30           BLAKE       01-MAY-81      2850      9400
    30          TURNER       08-SEP-81      1500      9400
    30          MARTIN       28-SEP-81      1250      9400
    30          JAMES        03-DEC-81      950       9400
    
    13 rows selected.
    

    いくつかの重要な注意事項
    (1)分析関数は、最後のORDER BY句を除いて、クエリで実行される最後の一連の操作です。分析関数が処理される前に、すべての結合とすべてのWHERE、GROUP BY、およびHAVING句が完了します。したがって、分析関数は選択リストまたはORDER BY句にのみ表示できます。
    (2)分析関数は通常、累積、移動、中央揃え、およびレポートの集計を計算するために使用されます。

    オラクルの分析関数のこの詳細な説明が気に入っていただければ幸いです(パーティション句による)

    関連記事
    OracleのLEAD関数
    OracleのDENSE関数
    OracleLISTAGG関数
    グループ関数を使用したデータの集約
    https://docs.oracle.com/cd/E11882_01/ server.112 / e41084 / features004.htm


    1. PostgreSQLで重複する日付をテストする方法

    2. MySQLで現在の日付と時刻を取得する方法

    3. Oracle10g-最適化WHEREISNOT NULL

    4. Postgresは手動でシーケンスを変更します