グループでの分値は、Oracleアナリティック機能
-
20-09-2019 - |
質問
私は分析関数での作業に新たなんです。
DEPT EMP SALARY ---- ----- ------ 10 MARY 100000 10 JOHN 200000 10 SCOTT 300000 20 BOB 100000 20 BETTY 200000 30 ALAN 100000 30 TOM 200000 30 JEFF 300000
私は最低賃金との部門と従業員を望んでます。
結果は次のようになります。
DEPT EMP SALARY ---- ----- ------ 10 MARY 100000 20 BOB 100000 30 ALAN 100000
編集:ここで私は(それは同様GROUP BY句でスタッフを望んでいるとしてではなく、もちろん、それは動作しません)しているSQLがあります:
SELECT dept, emp, MIN(salary) KEEP (DENSE_RANK FIRST ORDER BY salary) FROM mytable GROUP BY dept
解決
私はランク()関数は、2つの理由から、これを移動するための方法ではないと思われる。
まず、それはおそらく、MIN()よりも効率が低い - ベースの方法
この理由は、クエリは、それがデータをスキャンし、ランクが再度読み、このリストによって、後に割り当てられますよう、部門ごとに、すべての給与の順序付けられたリストを維持しなければならないということです。明らかにこれのために活用することができるインデックスが存在しない場合に、最後のデータ項目が読み込まれるまで、あなたはランクを割り当てることはできませんし、リストのメンテナンスは高価であります。
ランク()関数の性能がスキャンされる要素の総数に依存し、したがって、数がディスクにソート流出は、パフォーマンスが崩壊することが十分である場合。
これはおそらく、より効率的です。
select dept,
emp,
salary
from
(
SELECT dept,
emp,
salary,
Min(salary) Over (Partition By dept) min_salary
FROM mytable
)
where salary = min_salary
/
このメソッドは、クエリがこれまでに遭遇した最小値の部門ごとに単一の値を維持することが必要です。新しい最小に遭遇した場合、既存の値が変更され、そうでない場合、新しい値は破棄されます。メモリに保持されなければならない要素の総数は、部署の数ではなく、スキャンされた行の数に関連している。
これは、Oracleがランクは本当にこのケースで計算する必要はありませんが、私はそれに賭けるしないことを認識するためにコードパスを持っている可能性があります。
()ランクを嫌うための第二の理由はそれだけで間違った質問に答えることです。質問は、それが「どのレコードが部門ごとに最小で給料を持っている」ある「どのレコードは、部門ごとの給与が発注昇順されている最初のランキングがある給料を持っている」ではありません。それは、少なくとも、私には大きな違いになります。
他のヒント
私はあなたの元のクエリとかなり接近していたと思います。以下は実行して、テストケースに一致するだろう。
SELECT dept,
MIN(emp) KEEP(DENSE_RANK FIRST ORDER BY salary, ROWID) AS emp,
MIN(salary) KEEP (DENSE_RANK FIRST ORDER BY salary, ROWID) AS salary
FROM mytable
GROUP BY dept
RANKとは対照的に()ソリューション、これは、部門ごとに最大1つの行に保証します。しかし、それは問題でヒント:何が最低給与上の二人の従業員がある部署になりますか? RANK()ソリューションは、両方の従業員を返します - 部門のための複数の行を。この答えは、任意に1を選択し、部門の一つだけがありますことを確認します。
あなたはRANK()
構文を使用することができます。従業員が自分の給料がどのように大規模に関しては、部門内にランクどこたとえば、このクエリはあなたを教えてくれます。
SELECT
dept,
emp,
salary,
(RANK() OVER (PARTITION BY dept ORDER BY salary)) salary_rank_within_dept
FROM EMPLOYEES
あなたは、この場所salary_rank_within_dept = 1
から問い合わせることができ
SELECT * FROM
(
SELECT
dept,
emp,
salary,
(RANK() OVER (PARTITION BY dept ORDER BY salary)) salary_rank_within_dept
FROM EMPLOYEES
)
WHERE salary_rank_within_dept = 1
select e2.dept, e2.emp, e2.salary
from employee e2
where e2.salary = (select min(e1.salary) from employee e1)