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

ROWNUMなしで上位N行を選択しますか?

    これは宿題なので、答えではなくヒントです。分析関数を使用することをお勧めします。 ROW_NUMBER、RANK、またはDENSE_RANKは、タイの処理方法に応じて機能します。

    分析関数も許可されていない場合、私が想像できる他のオプションは、実際には決して実際に書くことは決してないだろうというものです。

    SELECT name, salary
      FROM staff s1
     WHERE (SELECT COUNT(*)
              FROM staff s2
             WHERE s1.salary < s2.salary) <= 3
    

    パフォーマンスに関しては、クエリプランのCOST番号に依存しません。これは単なる見積もりであり、通常、異なるSQLステートメントのプラン間でコストを比較することはできません。クエリが実際に実行する一貫性のある取得の数のようなものを見て、テーブルの行数が増えるにつれてクエリのパフォーマンスがどのようにスケーリングするかを検討する方がはるかに良いでしょう。 3番目のオプションは、STAFFテーブルを2回スキャンする必要があるという理由だけで、他の2つのオプションよりも大幅に効率が低下します。

    STAFFテーブルがないので、SCOTTスキーマのEMPテーブルを使用します

    分析関数ソリューションは、実際にはROWNUMソリューションと同様に7つの一貫した取得を実行します

    Wrote file afiedt.buf
    
      1  select ename, sal
      2    from( select ename,
      3                 sal,
      4                 rank() over (order by sal) rnk
      5            from emp )
      6*  where rnk <= 3
    SQL> /
    
    ENAME             SAL
    ---------- ----------
    smith             800
    SM0               950
    ADAMS            1110
    
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 3291446077
    
    --------------------------------------------------------------------------------
    -
    | Id  | Operation                | Name | Rows  | Bytes | Cost (%CPU)| Time
    |
    --------------------------------------------------------------------------------
    -
    |   0 | SELECT STATEMENT         |      |    14 |   672 |     4  (25)| 00:00:01
    |*  1 |  VIEW                    |      |    14 |   672 |     4  (25)| 00:00:01
    |*  2 |   WINDOW SORT PUSHED RANK|      |    14 |   140 |     4  (25)| 00:00:01
    |   3 |    TABLE ACCESS FULL     | EMP  |    14 |   140 |     3   (0)| 00:00:01
    --------------------------------------------------------------------------------
    -
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter("RNK"<=3)
       2 - filter(RANK() OVER ( ORDER BY "SAL")<=3)
    
    
    Statistics
    ----------------------------------------------------------
              0  recursive calls
              0  db block gets
              7  consistent gets
              0  physical reads
              0  redo size
            668  bytes sent via SQL*Net to client
            524  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              1  sorts (memory)
              0  sorts (disk)
              3  rows processed
    
    SQL> select ename, sal
      2    from( select ename, sal
      3            from emp
      4           order by sal )
      5   where rownum <= 3;
    
    ENAME             SAL
    ---------- ----------
    smith             800
    SM0               950
    ADAMS            1110
    
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 1744961472
    
    --------------------------------------------------------------------------------
    | Id  | Operation               | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    --------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT        |      |     3 |   105 |     4  (25)| 00:00:01 |
    |*  1 |  COUNT STOPKEY          |      |       |       |            |          |
    |   2 |   VIEW                  |      |    14 |   490 |     4  (25)| 00:00:01 |
    |*  3 |    SORT ORDER BY STOPKEY|      |    14 |   140 |     4  (25)| 00:00:01 |
    |   4 |     TABLE ACCESS FULL   | EMP  |    14 |   140 |     3   (0)| 00:00:01 |
    --------------------------------------------------------------------------------
    
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter(ROWNUM<=3)
       3 - filter(ROWNUM<=3)
    
    
    Statistics
    ----------------------------------------------------------
              1  recursive calls
              0  db block gets
              7  consistent gets
              0  physical reads
              0  redo size
            668  bytes sent via SQL*Net to client
            524  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              1  sorts (memory)
              0  sorts (disk)
              3  rows processed
    

    ただし、COUNT(*)ソリューションは、実際には99回の一貫した取得を実行し、テーブルのフルスキャンを2回実行する必要があるため、効率が10倍以上低下します。また、テーブルの行数が増えると、スケーリングが大幅に悪化します

    SQL> select ename, sal
      2    from emp e1
      3   where (select count(*) from emp e2 where e1.sal < e2.sal) <= 3;
    
    ENAME             SAL
    ---------- ----------
    JONES            2975
    SCOTT            3000
    KING             5000
    FORD             3000
    FOO
    
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 2649664444
    
    ----------------------------------------------------------------------------
    | Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    ----------------------------------------------------------------------------
    |   0 | SELECT STATEMENT    |      |    14 |   140 |    24   (0)| 00:00:01 |
    |*  1 |  FILTER             |      |       |       |            |          |
    |   2 |   TABLE ACCESS FULL | EMP  |    14 |   140 |     3   (0)| 00:00:01 |
    |   3 |   SORT AGGREGATE    |      |     1 |     4 |            |          |
    |*  4 |    TABLE ACCESS FULL| EMP  |     1 |     4 |     3   (0)| 00:00:01 |
    ----------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter( (SELECT COUNT(*) FROM "EMP" "E2" WHERE
                  "E2"."SAL">:B1)<=3)
       4 - filter("E2"."SAL">:B1)
    
    
    Statistics
    ----------------------------------------------------------
              0  recursive calls
              0  db block gets
             99  consistent gets
              0  physical reads
              0  redo size
            691  bytes sent via SQL*Net to client
            524  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
              5  rows processed
    


    1. MySQLResultSetのスクロール可能/更新可能が期待どおりに機能しない

    2. 年を保存するためのMySQLタイプ:SmallintまたはVarcharまたはDate?

    3. フィールド(レコードのIDではない)へのPostgreSQLシーケンスの作成

    4. psycopg2と無限のPythonスクリプト