What is the simplest way to get the nth highest value from a result set using plain SQL?
The result set would be huge, thus need to consider performance too.
This is the T-SQL (SQL-Server 2005 and greater) approach using 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
If you want all rows with the same value use DENSE RANK instead.
Difference between ROW_NUMBER, RANK and DENSE_RANK
This article talks about this question in depth, and I will quote code from it below:
Solution 1: This SQL to find the Nth highest salary should work in SQL Server, MySQL, DB2, Oracle, Teradata, and almost any other RDBMS: (note: low performance because of subquery)
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)
The most important thing to understand in the query above is that the subquery is evaluated each and every time a row is processed by the outer query. In other words, the inner query can not be processed independently of the outer query since the inner query uses the Emp1 value as well.
In order to find the Nth highest salary, we just find the salary that has exactly N-1 salaries greater than itself.
Solution 2: Find the nth highest salary using the TOP keyword in SQL Server
SELECT TOP 1 Salary
FROM (
SELECT DISTINCT TOP N Salary
FROM Employee
ORDER BY Salary DESC
) AS Emp
ORDER BY Salary
Solution 3: Find the nth highest salary in SQL Server without using TOP
SELECT Salary FROM Employee
ORDER BY Salary DESC OFFSET N-1 ROW(S)
FETCH FIRST ROW ONLY
Note that I haven’t personally tested the SQL above, and I believe that it will only work in SQL Server 2012 and up.
Solution 4: Works in MySQL
SELECT Salary FROM Employee
ORDER BY Salary DESC LIMIT n-1,1
The LIMIT clause takes two arguments in that query – the first argument specifies the offset of the first row to return, and the second specifies the maximum number of rows to return.
Solution 5: Works in Oracle
select * from (
select Emp.*,
row_number() over (order by Salary DESC) rownumb
from Employee Emp
)
where rownumb = n; /*n is nth highest salary*/
Solution 6: Works in Oracle way 2
select * FROM (
select EmployeeID, Salary
,rank() over (order by Salary DESC) ranking
from Employee
)
WHERE ranking = N;