Use ROW_NUMBER(if you want a single) or DENSE_RANK(for all related rows):
WITH CTE AS
(
SELECT EmpID, EmpName, EmpSalary,
RN = ROW_NUMBER() OVER (ORDER BY EmpSalary DESC)
FROM dbo.Salary
)
SELECT EmpID, EmpName, EmpSalary
FROM CTE
WHERE RN = @NthRow
SELECT *
FROM Employee Emp1
WHERE (N-1) = (
SELECT COUNT(DISTINCT(Emp2.Salary))
FROM Employee Emp2
WHERE Emp2.Salary > Emp1.Salary)
Explanation
The query above can be quite confusing if you have not seen anything like it before – the inner query is what’s called a correlated sub-query because the inner query (the subquery) uses a value from the outer query (in this case the Emp1 table) in it’s WHERE clause.
In 2008 we can use ROW_NUMBER() OVER (ORDER BY EmpSalary DESC) to get a rank without ties that we can use.
For example we can get the 8th highest this way, or change @N to something else or use it as a parameter in a function if you like.
DECLARE @N INT = 8;
WITH rankedSalaries AS
(
SELECT
EmpID
,EmpName
,EmpSalary,
,RN = ROW_NUMBER() OVER (ORDER BY EmpSalary DESC)
FROM salary
)
SELECT
EmpID
,EmpName
,EmpSalary
FROM rankedSalaries
WHERE RN = @N;
In SQL Server 2012 as you might know this is performed more intuitively using LAG().
This is mysql query for fetching the nth highest salary from the table emp.
We use "LIMIT" here as an alternative to "TOP" and the parameter (n-1) shows after which row to start from and the second parameter shows how many rows to show starting from the (n-1)th row. "LIMIT" accepts single parameter also which represents the number of rows to show starting from 0th(or 1st).
select distinct * from emp order by sal desc limit (n-1),1;
declare @nHighestSalary as int
set @nHighestSalary = 3
SELECT TOP 1 salary FROM (
SELECT TOP @nHighestSalary salary
FROM employees
ORDER BY salary DESC) AS emp
ORDER BY salary ASC
To query the nth highest bonus, say n=10, using AdventureWorks2012, Try Following code
USE AdventureWorks2012;
GO
SELECT * FROM Sales.SalesPerson;
GO
DECLARE @grade INT;
SET @grade = 10;
SELECT MIN(Bonus)
FROM (SELECT TOP (@grade) Bonus FROM (SELECT DISTINCT(Bonus) FROM Sales.SalesPerson) AS a ORDER BY Bonus DESC) AS g
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)
select * from emp x where &no=(select count(*) from emp y where y.sal>=x.sal);
this will give take input from user and then will tell the nth maximum number.I have taken example of emp table in oracle and to display nth maximum salaried employee info
Output
Enter value for no: 5
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
----- ---------- --------- ---------- --------- ---------- ---------- ----------
7698 BLAKE MANAGER 7839 01-MAY-81 3000 30
7788 SCOTT ANALYST 7566 19-APR-87 3000 20
7902 FORD ANALYST 7566 03-DEC-81 3000 20
Enter value for no: 14
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
----- ---------- --------- ---------- --------- ---------- ---------- ----------
7369 SMITH CLERK 7902 17-DEC-80 800 20
another way to find last highest data based on date
SELECT A.JID,A.EntryDate,RefundDate,Comments,Refund, ActionBy FROM (
(select JID, Max(EntryDate) AS EntryDate from refundrequested GROUP BY JID) A
Inner JOIN (SELECT JID,ENTRYDATE,refundDate,Comments,refund,ActionBy from refundrequested) B
ON A.JID=B.JID AND A.EntryDate = B.EntryDate)
Hi One more example to write this using common table expression:
with cte as
(SELECT TOP 3 salary
FROM salary
ORDER BY salary DESC)
select top 1 salary from cte
with cte as
(select e.Name,s.salary ,DENSE_RANK ()over ( order by salary desc) sal_rank
from salary s left join employee e
on s.EmpID=e.EmpID)
select Name,salary from cte where sal_rank=3
;With CTE as
(
select salary
,RANK(order by salary desc) as Rnk
from table
)
select * from CTE where Rnk = @yourVariable
Second Opinion,
Declare @yourVariable int = 2
Select top 1 * from
(
select distinct top(@yourVariable) salary
from Employees
order by salary desc
)as a
order by a.salary asc
select * from Employees
order by salary desc
Now I am going to insert 8 rows into this table by running below insert statement.
insert into Employee values(1,'Neeraj',45000)
insert into Employee values(2,'Ankit',5000)
insert into Employee values(3,'Akshay',6000)
insert into Employee values(4,'Ramesh',7600)
insert into Employee values(5,'Vikas',4000)
insert into Employee values(7,'Neha',8500)
insert into Employee values(8,'Shivika',4500)
insert into Employee values(9,'Tarun',9500)
Now we will find out 3rd highest Basic_sal from the above table using different queries.
I have run the below query in management studio and below is the result.
select * from Employee order by Basic_Sal desc
We can see in the above image that 3rd highest Basic Salary would be 8500. I am writing 3 different ways of doing the same. By running all three mentioned below queries we will get same result i.e. 8500.
First Way: - Using row number function
select Ename,Basic_sal
from(
select Ename,Basic_Sal,ROW_NUMBER() over (order by Basic_Sal desc) as rowid from Employee
)A
where rowid=2
If you want optimize way means use TOP Keyword, So the nth max and min salaries query as follows but the queries look like a tricky as in reverse order by using aggregate function names:
N maximum salary:
SELECT MIN(EmpSalary)
FROM Salary
WHERE EmpSalary IN(SELECT TOP N EmpSalary FROM Salary ORDER BY EmpSalary DESC)
for Ex: 3 maximum salary:
SELECT MIN(EmpSalary)
FROM Salary
WHERE EmpSalary IN(SELECT TOP 3 EmpSalary FROM Salary ORDER BY EmpSalary DESC)
N minimum salary:
SELECT MAX(EmpSalary)
FROM Salary
WHERE EmpSalary IN(SELECT TOP N EmpSalary FROM Salary ORDER BY EmpSalary ASC)
for Ex: 3 minimum salary:
SELECT MAX(EmpSalary)
FROM Salary
WHERE EmpSalary IN(SELECT TOP 3 EmpSalary FROM Salary ORDER BY EmpSalary ASC)
SELECT MIN(EmpSalary) from (
SELECT EmpSalary from Employee ORDER BY EmpSalary DESC LIMIT 3
);
You can here just change the nth value after the LIMIT constraint.
Here in this the Sub query Select EmpSalary from Employee Order by EmpSalary DESC Limit 3; would return the top 3 salaries of the Employees. Out of the result we will choose the Minimum salary using MIN command to get the 3rd TOP salary of the employee.
Refer following query for getting nth highest salary. By this way you get nth highest salary in MYSQL. If you want get nth lowest salary only you need to replace DESC by ASC in the query.
Find Nth highest salary from a table. Here is a way to do this task using dense_rank() function.
select linkorder from u_links
select max(linkorder) from u_links
select max(linkorder) from u_links where linkorder < (select max(linkorder) from u_links)
select top 1 linkorder
from ( select distinct top 2 linkorder from u_links order by linkorder desc) tmp
order by linkorder asc
DENSE_RANK :
1. DENSE_RANK computes the rank of a row in an ordered group of rows and returns the rank as a NUMBER. The ranks are consecutive integers beginning with 1.
2. This function accepts arguments as any numeric data type and returns NUMBER.
3. As an analytic function, DENSE_RANK computes the rank of each row returned from a query with respect to the other rows, based on the values of the value_exprs in the order_by_clause.
4. In the above query the rank is returned based on sal of the employee table. In case of tie, it assigns equal rank to all the rows.
WITH result AS (
SELECT linkorder ,DENSE_RANK() OVER ( ORDER BY linkorder DESC ) AS DanseRank
FROM u_links )
SELECT TOP 1 linkorder FROM result WHERE DanseRank = 5
finding Nth max value using CTE and FIRST_VALUE function.
-- 5th max salary
;WITH CTE_NTH_SAL AS
(SELECT FIRST_VALUE(ESAL) OVER(ORDER BY ESAL DESC) AS ESAL,
1 AS ID
FROM EMPLOYEE
UNION ALL
SELECT FIRST_VALUE(EMP.ESAL) OVER(ORDER BY EMP.ESAL DESC) AS ESAL,
ID
FROM EMPLOYEE EMP,
(SELECT ESAL,
ID+1 AS ID
FROM CTE_NTH_SAL) CTE_NTH_SAL
WHERE EMP.ESAL<CTE_NTH_SAL.ESAL
AND CTE_NTH_SAL.ID<=5 )
SELECT DISTINCT ESAL
FROM CTE_NTH_SAL
WHERE ID=5
Answering this question from the point of view of SQL Server as this is posted in the SQL Server section.
There many approaches of getting Nth salary and we can classify these approaches in two sections one using ANSI SQL approach and other using TSQL approach. You can also check out this find nth highest salary youtube video which shows things practically. Let’s try to cover three ways of writing this SQL.
Approach number 1: - ANSI SQL: - Using Simple order by and top keyword.
Approach number 2: - ANSI SQL: - Using Co-related subqueries.
Approach number 3: - TSQL: - using Fetch Next
Approach number 1: - Using simple order by and top.
In this approach we will using combination of order by and top keyword. We can divide our thinking process in to 4 steps: -
Step 1: - Descending :- Whatever data we have first make it descending by using order by clause.
Step 2:- Then use TOP keyword and select TOP N. Where N stands for which highest salary rank you want.
Step 3: - Ascending: - Make the data ascending.
Step 4:- Select top 1 .There you are done.
So, if you put down the above 4 logical steps in SQL it comes up something as shown below.
Below is the text of SQL in case you want to execute and test the same.
select top 1 * from (select top 2 EmployeeSalary from tblEmployee
order by EmployeeSalary desc) as innerquery order by EmployeeSalary
asc
Parameterization issue of Approach number 1
One of the biggest issues of Approach number 1 is “PARAMETERIZATION”.
If you want to wrap up the above SQL in to a stored procedure and give input which top salary you want as a parameter, it would be difficult by Approach number 1.
One of the things you can do with Approach number 1 is make it a dynamic SQL but that would not be an elegant solution. Let’s check out Approach number 2 which is an ANSI SQL approach.
Approach number 2: - Using Co-related subqueries.
Below is how co-related subquery solution will look like. In case you are new to Co-related subquery. Co-related subquery is a query which a query inside query. The outer query first evaluates, sends the record to the inner query, inner query then evaluates and sends it to the outer query.
“3” in the query is the top salary we want to find out.
Select E1.EmployeeSalary from tblEmployee as E1 where 3=(Select
count(*) from tblEmployee as E2 Where
E2.EmployeeSalary>=E1.EmployeeSalary)
So in the above query we have an outer query:-
Select E1.EmployeeSalary from tblEmployee as E1
and inner query is in the where clause. Watch those BOLD’s which indicate how the outer table alias is referred in the where clause which makes co-related evaluate inner and outer query to and fro: -
where 3=(Select count(*) from tblEmployee as E2 Where
E2.EmployeeSalary>=E1.EmployeeSalary)
So now let’s say you have records like 3000, 4000 ,1000 and 100 so below will be the steps: -
First 3000 will be send to the inner query.
Inner query will now check how many record values are greater than or equal to 3000. If the number of record counts is not equal, it will take next value which is 4000. Now for 3000 there are only 2 values which is greater than or equal, 3000 and 4000. So, Is number record count 2>-=3? .NO, so it takes second value which is 4000.
Again for 4000 how many record values are greater than or equal. If the number of record count is not equal, it will take next value which is 1000.
Now 1000 has 3 records more or equal than 1000, (3000,4000 and 1000 himself). This is where co-related stops and exits and gives the final output.
Approach number 3: - TSQL fetch and Next.
Third approach is by using TSQL. By using Fetch and Next, we can get the Nth highest easily.
But please do note, TSQL code will not work for other databases we will need to rewrite the whole code again.
It would be a three-step process:-
Step 1 Distinct and Order by descending: - First apply distinct and order by which made the salaries descending as well as weed off the duplicates.
Step 2 Use Offset: - Use TSQL Offset and get the top N-1 rows. Where N is the highest salary we want to get. Offset takes the number of rows specified, leaving the other rows. Why (N-1) because it starts from zero.
Step 3 Use Fetch: - Use fetch and get the first row. That row has the highest salary.
The SQL looks something as shown below.
Performance comparison
Below is the SQL plan for performance comparison.
Below is the plan for top and order by.
Below is the plan for co-related queries. You can see the number of operators are quiet high in numbers. So surely co-related would perform bad for huge data.
Below is TSQL query plan which is better than cor-related.
So, summing up we can compare more holistically as given in the below table.
(assuming that multiple employees can have same salary; i.e. ties can exist)
If you want ALL the rows with the nth highest salary
select * from table_name
where salary = (
select distinct(salary) as sal from
table_name order by sal desc
limit n-1, 1
);
If you want only FIRST k rows with the nth highest salary
select * from table_name
where salary = (
select distinct(salary) as sal from
table_name order by sal desc
limit n-1, 1
) limit k; -- you can also apply `order by` in this line