5

宿題を手伝ってくれることを願っています:)

上位 N 位の高給の従業員を出力するクエリを作成する必要があります。

私のバージョンは完全に正常に動作します。
たとえば、トップ 3:

SELECT name, salary
FROM staff
WHERE salary IN ( SELECT * 
                  FROM ( SELECT salary
                         FROM staff 
                         ORDER BY salary DESC ) 
                  WHERE ROWNUM <= 3 )
ORDER BY salary DESC
;

これにより、上位 3 位に含まれる同じ給与の従業員も出力されることに注意してください。

1: マイク、4080
2: スティーブ、2800
2: スーザン、2800
2: ジャック、2800
3: クロエ、1400


しかし今、私たちの先生は私たちが を使用することを許可していませんROWNUM
私は広範囲に検索しましたが、使用できるものは何も見つかりませんでした。


Justin Caves のヒントのおかげで、私の 2 番目の解決策です。

最初に私はこれを試しました:

SELECT name, salary, ( rank() OVER ( ORDER BY salary DESC ) ) as myorder
FROM staff
WHERE myorder <= 3
;

エラーメッセージは次のとおりです:「myorder: 無効な識別子」

DCookie のおかげで、次のことが明確になりました。

「[...] where句が評価された後に分析が適用されるため、myorderが無効な識別子であるというエラーが発生します。」

SELECT をラップすると、これが解決されます。

SELECT *
FROM ( SELECT name, salary, rank() OVER ( ORDER BY salary DESC ) as myorder FROM staff )
WHERE myorder <= 3
;

私の先生は再びストライキをし、そのような風変わりな分析機能を許可しません。

@Justin Caves の3 番目のソリューション。

「分析関数も許可されていない場合、私が想像できるもう1つのオプション-実際には決して、実際に書くことのないものは、次のようなものになるでしょう」

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

5 に答える 5

11

これは宿題なので、答えではなくヒントです。分析関数を使用する必要があります。同順位の処理方法に応じて、ROW_NUMBER、RANK、または DENSE_RANK を使用できます。

分析関数も許可されていない場合、私が想像できるもう1つのオプション-実際には決して、決して、実際に書くことのないものは、次のようなものになります

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 分の 1 の効率しかありません。また、テーブルの行数が増えると、スケーリングが大幅に悪化します

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
于 2011-04-12T14:17:50.153 に答える
3

ステートメントを別の選択でラップする必要がある理由は、外側の選択ステートメントが、結果セットを必要な行番号に制限するステートメントであるためです。分析に関する役立つリンクを次に示します。内部選択を単独で実行すると、なぜこれを行う必要があるかがわかります。where句が評価された後に分析が適用されるため、 myorder が無効な識別子であるというエラーが発生します。

于 2011-04-12T16:06:47.247 に答える
1

オラクル?ウィンドウ関数はどうですか?

select * from 
(SELECT s.*, row_number over (order by salary desc ) as rn FROM staff s )
where rn <=3
于 2011-04-12T14:18:39.513 に答える
0

When you use count(distinct <exp>), equal ranking top salaries will be treated as tie ranks.

select NAME, SALARY
from  STAFF STAFF1
where 3 >= ( select count(distinct STAFF2.SALARY) RANK
               from STAFF STAFF2
              where STAFF2.SALARY >= STAFF1.SALARY)
于 2014-02-16T13:11:22.270 に答える