Reputation: 1135
I need to fetch all details of employee with third highest salary in the most efficient way.
My query:
select(SELECT MIN(Salary)
FROM (SELECT * TOP (3) Salary
FROM Employees
ORDER BY Salary)
Is there any issue in my query.how can i correct my query.Please help.
Upvotes: 2
Views: 854
Reputation: 524
There are a few ways that you can go about doing this. Two possible ways are
row_number
(or another windowing function, e.g. rank
or dense_rank
)top
on a subquery and then subsequntly on the result setI would suggest not using row_number
, since that would require more cpu, and, instead use the latter of the above two approaches.
Below are test cases for both, and what is shown is that the subquery approach runs in less than a quarter of the time.
create table #Salary (
PersonId int identity(1, 1) primary key clustered,
SalaryAmt decimal(16, 2) not null);
/* Insert some test data ... */
insert #Salary (
SalaryAmt)
select top (10000000)
abs(checksum(newid()) % 1000000)
from sys.all_columns a
cross join sys.all_columns b
set statistics io on;
set statistics time on;
select *
from (
select *,
RowNum = row_number() over (order by SalaryAmt desc)
from #Salary) a
where RowNum = 3;
set statistics time off;
set statistics io off;
checkpoint;
go
dbcc dropcleanbuffers;
go
set statistics io on;
set statistics time on;
select top 1 *
from (
select top 3 *
from #Salary
order by SalaryAmt desc) top_3
order by SalaryAmt;
set statistics time off;
set statistics io off;
The results are below:
SQL Server parse and compile time: CPU time = 0 ms, elapsed time = 1 ms. PersonId SalaryAmt RowNum ----------- --------------------------------------- -------------------- 1427822 999999.00 3 Table '#Salary_____________________________________________________________________________________________________________000000000007'. Scan count 9, logical reads 27219, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. SQL Server Execution Times: CPU time = 17123 ms, elapsed time = 2361 ms. DBCC execution completed. If DBCC printed error messages, contact your system administrator. SQL Server parse and compile time: CPU time = 0 ms, elapsed time = 0 ms. PersonId SalaryAmt ----------- --------------------------------------- 1427822 999999.00 Table '#Salary_____________________________________________________________________________________________________________000000000007'. Scan count 9, logical reads 27219, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. SQL Server Execution Times: CPU time = 4282 ms, elapsed time = 570 ms.
Hope this helps.
Upvotes: 1
Reputation: 28895
You can use Rownumber:Here i partitioned by empid to avoid ties
;With cte
as
(
select *,row_number() over (partition by empid order by salary desc) as rownum
from
table
)
select * from cte where rownum=3
if you want to use your query:
SELECT MIN(Salary
FROM (
SELECT TOP (3) Salary
FROM Employees
ORDER BY Salary
)b
Upvotes: 1
Reputation: 6178
use RANK
; WITH T AS
(
SELECT * , RANK() OVER (ORDER BY SalaryDESC) as rk
FROM Employees
)
Select TOP(1) *
FROM T
WHERE T.rk=3
Upvotes: 2