プレーン SQL を使用して結果セットからn番目に高い値を取得する最も簡単な方法は何ですか?
結果セットは膨大になるため、パフォーマンスも考慮する必要があります。
これは、以下を使用した T-SQL (SQL-Server 2005 以降) のアプローチROW_NUMBER
です。
WITH CTE AS
(
SELECT
Col1, Col2, ValueCol,
RN = ROW_NUMBER() OVER (ORDER BY ValueCol DESC) -- change to ASC if you want lowest first
FROM
dbo.TableName
)
SELECT
Col1, Col2, ValueCol
FROM
CTE
WHERE
RN = @nthhighestvalue
同じ値を持つすべての行が必要な場合は、DENSE RANK
代わりに使用します。
この記事では、この質問について詳しく説明しています。コードを以下に引用します。
解決策 1: N 番目に高い給与を見つけるこの SQL は、SQL Server、MySQL、DB2、Oracle、Teradata、およびその他のほぼすべての RDBMS で機能するはずです: (注: サブクエリのためパフォーマンスが低下します)
SELECT * /*This is the outer query part */
FROM Employee Emp1
WHERE (N-1) = ( /* Subquery starts here */
SELECT COUNT(DISTINCT(Emp2.Salary))
FROM Employee Emp2
WHERE Emp2.Salary > Emp1.Salary)
上記のクエリで理解しておくべき最も重要なことは、行が外側のクエリによって処理されるたびにサブクエリが評価されるということです。つまり、内側のクエリも Emp1 値を使用するため、内側のクエリを外側のクエリとは独立して処理することはできません。
N 番目に高い給与を見つけるには、それ自体よりちょうど N-1 高い給与を見つけるだけです。
解決策 2: SQL Server で TOP キーワードを使用して n 番目に高い給与を検索する
SELECT TOP 1 Salary
FROM (
SELECT DISTINCT TOP N Salary
FROM Employee
ORDER BY Salary DESC
) AS Emp
ORDER BY Salary
解決策 3: TOP を使用せずに SQL Server で n 番目に高い給与を見つける
SELECT Salary FROM Employee
ORDER BY Salary DESC OFFSET N-1 ROW(S)
FETCH FIRST ROW ONLY
上記の SQL を個人的にテストしていないことに注意してください。SQL Server 2012 以降でのみ機能すると思います。
解決策 4: MySQL で動作する
SELECT Salary FROM Employee
ORDER BY Salary DESC LIMIT n-1,1
LIMIT 句はそのクエリで 2 つの引数を取ります。最初の引数は返す最初の行のオフセットを指定し、2 番目の引数は返す行の最大数を指定します。
解決策 5: Oracle で動作する
select * from (
select Emp.*,
row_number() over (order by Salary DESC) rownumb
from Employee Emp
)
where rownumb = n; /*n is nth highest salary*/
解決策 6:オラクルの方法 2 で動作する
select * FROM (
select EmployeeID, Salary
,rank() over (order by Salary DESC) ranking
from Employee
)
WHERE ranking = N;
5 番目に高い給与を見つけたいとしましょう。まず、最初の 5 つの個別の給与を降順で取得し、最後の給与が 5 番目に高い給与になるようにします (内部クエリを参照)。次に、それを昇順に並べ替えて、最初のものを取ります。
SELECT TOP 1 Salary FROM
(
SELECT DISTINCT TOP 5 Salary
FROM Employee
ORDER BY Salary DESC) t
ORDER BY Salary ASC
順序付けられた番号付きのデータセットを作成することから始めて、そこから選択します。正確な構文は RDBMS によって異なりますが、たとえば、Oracle では次のことができます。
SELECT ROWNUM, SOMEVAL
FROM (SELECT SOMEVAL FROM SOMETABLE ORDER BY SOMEVAL DESC)
上記のセットを考えると、次のことができます
SELECT SOMEVAL WHERE ROWNUM = :N
オラクルの場合:
SELECT * FROM (
SELECT col1, ROW_NUMBER()OVER(ORDER BY col1) rnum_col1 FROM table1
) WHERE rnum_col1 = 10;
一般的なデータベースでは、サブクエリと 2 つの でこれを行うことができますorder by
。問題は、top/limit/rownum 構文が標準ではないことです。一部のデータベースでは、次のように記述します。
サブクエリは、上位 'n' 個の最高給与値を一覧表示します。そのリストの最小値は、n 番目に高い給与になります。
`SELECT min(salary) FROM
(SELECT DISTINCT TOP n salary FROM EmployeeTable ORDER BY salary desc);`
例:- 3 番目の最高給与を検索する SQL クエリ
`SELECT min(salary) FROM
(SELECT DISTINCT TOP 3 salary FROM EmployeeTable ORDER BY salary desc);`
並べ替えのオーバーヘッドが発生する必要があります。私の例rownum
では、物理的な場所ではなく、並べ替えられた行番号です。
誰もが分析関数を使用してこれがどのように機能するかを示しているため、ここにその 1 つを示します。
select foo,bar, max(baz)
from
(
select *
from
(
select foo,bar,baz, row_number() over
(partition by some_identifier_that_Groups order by value DESC) rn
)
where rn = 1 -- get the highest value for each partition
) group by foo,bar