in

code for eternity !!!

community website for .net freaks ;-)

Technology

T-SQL Query to Find the Second Highest Column Value in a Table

One of my favorite technical interview question on SQL Server is "What query would you write to find the second highest column value in a table?" The question seems easy, however most developers fail to answer to this. If we had a table named Employee which had a column named Salary and we had to find the second highest Salary in the Employee table, the query for the same would be:

SELECT TOP 1 Salary FROM (SELECT TOP 2 Salary FROM Employee ORDER BY Salary DESC) AS E ORDER BY Salary ASC

If we ran the above query against the Employee table which had the following 5 rows:

1000
2000
3000
4000
5000

The subquery or the inner query would return the top 2 rows in descending Salary order which would be:

5000
4000

The outer query would then select the top 1 row from the subquery results in ascending Salary order which would be:

4000

Note that if we had to get the fourth highest Salary, we could do so by simply changing the subquery from TOP 2 to TOP 4

Cheers,
Raj

~~~ CODING FOR ETERNITY !!! ~~~

Published Jan 10 2008, 02:53 PM by raj
Filed under:

I would really appreciate votes / kicks for this blog post if you found it useful ;-)

  kick it on DotNetKicks.com     Receive Email Updates


Comments

 

Shankar said:

I have Faced this Quetion in Tech. Interview.It is vey nice solution,I was finding this solution since many days.

February 7, 2008 7:13 AM
 

jaysh said:

if there will present lots of employees who have same salary , then how will you get the 2nd hightest salaries of those employees.

February 14, 2008 1:20 AM
 

raj said:

Hi jaysh,

Good question. The answer to your question is really simple. If there were multiple employees having the same salaries, all you need to do is use group by in the inner query like this:

SELECT TOP 1 Salary FROM (SELECT TOP 2 Salary FROM Employee GROUP BY Salary ORDER BY Salary DESC) AS E ORDER BY Salary ASC

The inner query would now return only unique salaries in descending order and the outer query would then select the top 1 salary in reverse order based on the results from inner query.

Cheers,
Raj

~~~ CODING FOR ETERNITY !!! ~~~

February 14, 2008 2:03 AM
 

DotNetKicks.com said:

You've been kicked (a good thing) - Trackback from DotNetKicks.com

February 20, 2008 12:12 AM
 

Joe Webb said:

Another excellent post, Raj. Thanks!

Joe

February 20, 2008 5:39 AM
 

raj said:

Hi Joe,

Thanks for your encouraging feedback mate. Cheers.

Cheers,
Raj

~~~ CODING FOR ETERNITY !!! ~~~

February 20, 2008 5:53 AM
 

Chris F said:

The answer given solves the solution, but with SQL 2005 being out now for a number of years the most correct solution should be given in T-SQL 2005 syntax.

WITH Customer AS (

SELECT *, ROW_NUMBER() OVER (ORDER BY CustomerID) AS RowNumber

FROM cus_Customer

)

SELECT *

FROM Customer

WHERE RowNumber = 2

This also allows extra variations such as:

WHERE RowNumber >= 20

WHERE RowNumber BETWEEN 5 AND 10

WHERE RowNumber in (1, 4, 5, 6, 7, 10, 15)

February 20, 2008 10:42 PM
 

jaysh said:

hi

Thanx for this answer , But i didnt get how will i write top 1 and top 2 salary in a query. I have written a query for this , please check and tell me on this query that how to get all the employee's name of same salary

SELECT max(SALARY) as Sal FROM tbl_tips WHERE SALARY<>(SELECT MAX(SALARY) FROM tbl_tips)

February 21, 2008 10:08 PM
 

raj said:

Hi Chris,

Thanks for the suggestion :-) Will update the above post to also include your example as well :-)

Cheers,
Raj

~~~ CODING FOR ETERNITY !!! ~~~

February 23, 2008 6:04 AM
 

Egil said:

I am certainly not a SQL wizard, but please explain to me why the last ORDER BY is necessary.

Cant you just change the inner sub query to

"SELECT TOP 2 Salary FROM Employee ORDER BY Salary ASC"

and get

4000

5000

as the result, and from there just do the outer query without the ORDER BY, like so?

SELECT TOP 1 Salary FROM (SELECT TOP 2 Salary FROM Employee GROUP BY Salary ORDER BY Salary ASC)

February 25, 2008 3:38 PM
 

Rip said:

This may be a simpler solution to Jaysh's question:

SELECT TOP 1 Salary

FROM Employee

WHERE Salary not in (

  SELECT top 1 Salary

  FROM Employee

  ORDER BY Salary DESC)

ORDER BY Salary DESC

February 25, 2008 8:12 PM
 

raj said:

Hi Egil,

You wrote: Cant you just change the inner sub query to "SELECT TOP 2 Salary FROM Employee ORDER BY Salary ASC" and get 4000, 5000.

My reply: No, the above inner query would return 1000, 2000 instead of 4000, 5000. Thats because we are selecting top 2 rows after sorting all records in ascending order (1-9).

Cheers,
Raj

~~~ CODING FOR ETERNITY !!! ~~~

February 25, 2008 11:04 PM
 

raj said:

Hi Rip,

Thanks for your contribution :-) However, if we have many employees sharing the same salary, your query would surely work as long as we are interested in second highest value. However the moment you need the third highest value or the fourth highest value, you will have no choice but to add the GROUP BY clause in your sub query :-)

Try to get the third highest salary by executing your query for the following records:

1000
2000
3000
4000
4000
5000
5000

Cheers,
Raj

~~~ CODING FOR ETERNITY !!! ~~~

February 25, 2008 11:30 PM
 

Egil said:

ahh of course. should have figured that out by my self ;)

February 26, 2008 3:08 AM
 

Davod said:

I have been giving this for a few yers in interviews, and recently had an answer that I have never seen before.

delete from Table

where salary = (Select max(salary)

                             from table )

select MAX(salary)

from table

(He got one of the other ways as well)... Just an interesting approach, No?

February 26, 2008 6:39 AM
 

raj said:

Hi Davod,

I could not stop laughing when I read your comment. I would love to meet that great developer who gave you that solution ;-) Just that I would never want to have him as a co developer on any of my projects ;-)

Cheers,
Raj

~~~ CODING FOR ETERNITY !!! ~~~

February 26, 2008 7:27 AM
 

Daily Bits - February 26, 2008 | Alvin Ashcraft's Daily Geek Bits said:

Pingback from  Daily Bits - February 26, 2008 | Alvin Ashcraft's Daily Geek Bits

February 26, 2008 7:32 AM
 

Mike Borozdin said:

LOL, the comment that contained the DELETE clause made me laugh like mad!!!!!!

February 27, 2008 11:26 AM
 

Sumit said:

Hi All,

Hows this one to find second Highest...

"select max(salary) from test where salary not in (select max(salary) from test)"

March 3, 2008 4:12 AM
 

raj said:

Hi Sumit,

Thanks for your contribution. Your query would work as long as we are interested in the second highest value. But it wont give you the flexibility to get the third or the fourth highest value. Rip posted a similar solution (see above in comments) but his solution too has the same limitations.

But its really interesting to read so many different queries people come up to solve this ;-)

Cheers,
Raj

~~~ CODING FOR ETERNITY !!! ~~~

March 3, 2008 4:39 AM
 

Sumit said:

Hi Raj,

Thanks for ur nice post for getting Second or any other highest from a Table. As i think there is a flaw in ur Query. If there are two salary having same amount, then ur query returns wrong result.

I tried   it for Salary like:

Salary

55000

55000

45000

35000

Now it will return 55000 if ur query executed and with my query it returns 45000 that is right i think.

Regards,

Sumit

sumitarora.bit@gmail.com

March 5, 2008 12:09 AM
 

raj said:

Hi Sumit,

Can you please check out the 3rd comment from the top in which I have replied to a question by jaysh? In short, if you have multiple employees sharing the same salary, you can use GROUP BY to get appropriate results.

Cheers,
Raj

~~~ CODING FOR ETERNITY !!! ~~~

March 5, 2008 1:33 AM
 

Sumit said:

Raj,

Gud work. and Thanks.

Sumit

March 5, 2008 1:41 AM
 

caron said:

Hi Raj,

can you also help in finding the 2nd highest salary, employee name from each department id. Suppose there are 10 departments, then 2nd highest salary in each department along with employee name.

Thanks

March 31, 2008 4:01 AM
 

d_ser said:

hey guys, as a newbie here and with T-SQL I have a question for the following query, which is the one from the top pf the page.

SELECT TOP 1 Salary

FROM (SELECT TOP 2 Salary FROM Employee

            ORDER BY Salary DESC) AS E

ORDER BY Salary ASC

what is the role here of the "AS E" and why it doesn't work if I avoid it? Why declaring that alias is necessary is what I'm asking

April 1, 2008 2:57 PM
 

swaraj said:

how to serch high secend employees by sql query

April 3, 2008 7:45 AM
 

raj said:

Hi d_ser,

Derived tables MUST always have an alias otherwise your queries wont work. Click here for detailed info on the same. Hope this helps.

Cheers,
Raj

~~~ CODING FOR ETERNITY !!! ~~~

April 5, 2008 3:20 AM
 

d_ser said:

thanx raj

April 15, 2008 10:28 PM
 

Pawan said:

thanks Raj.... i was searching that query to find out  2nd top data in a table. nice solutions given by u ....

April 21, 2008 4:15 AM
 

tsql said:

Pingback from  tsql

April 28, 2008 9:42 PM
 

Dipti said:

Hey Raj...

Good Solution.....

What is the query to select the second last salary??

April 30, 2008 12:03 AM
 

Technology said:

After reading my earlier post T-SQL Query to Find the Second Highest Column Value in a Table a lot of

April 30, 2008 2:03 AM
 

raj said:

April 30, 2008 2:06 AM
 

Dipti said:

Thanks a lot!!!..appreciate ur reply..

Please let me know the query for first five highest salary?

April 30, 2008 2:45 AM
 

Vasant said:

Thanks, for that. but how to select top 5 Rows i.e from top rows 6 to top rows10. I didn't want output of top 5 row and after top 10 rows.

April 30, 2008 4:51 AM
 

Vasant said:

Hi Depti,

Let's try this

SELECT TOP 5 Salary FROM Salary ORDER BY Salary desc

Vasant

April 30, 2008 4:54 AM
 

Dipti said:

I think it should work...

April 30, 2008 5:14 AM
 

Vasant said:

Hi Raj,

I found query.........

SELECT TOP 5 tradedate FROM(SELECT TOP 5 tradedate FROM (SELECT TOP 10 tradedate FROM dbo.tbbankloanDetail GROUP BY tradedate ORDER BY tradedate desc)

AS E ORDER BY tradedate asc)AS b ORDER BY tradedate desc

Plze try it, If you have other way please putt it.

Vasant Jagtap

April 30, 2008 5:58 AM
 

ching said:

hey how to find duplicate values in a column n how to delete duplicate rows

May 16, 2008 4:45 AM
 

Vishal said:

Nice post...however, there is another way of doing it too...lets assume we need 3rd highest salary in a table employee..we can use this

select min(Emp_Sal) from Employee_Test where Emp_Sal in

(select distinct top 3 Emp_Sal from Employee_Test order by Emp_Sal desc)

May 20, 2008 3:54 AM
 

Vishal said:

Hi Ching,

you can use this

select <Columnmame> from table group by <columnname> having count(*)>1

May 20, 2008 3:56 AM
 

siddhartha said:

select e.salary from emp  e where 2 <(select count(distinct salary) from salary <e.salary)

May 21, 2008 4:22 AM
 

Digisha said:

with tmp as(

select SUM(purchase_price) as tp,SUM(purchase_price) as tp1 from dwpurchases dp, dwcustomer dc where dp.customer_key = dc.customer_key and dc.country = 'Australia' group by dc.state )

select dc.state from dwpurchases dp, dwcustomer dc where dp.customer_key = dc.customer_key and dc.country = 'Australia'

group by dc.state

having sum(purchase_price) = (select MAX(tp) from tmp);

 how to list second most state?

May 23, 2008 3:42 AM
 

parth.patel said:

Hi Digisha,

It's easy. You can DENSE_RANK() function.

with tmpSum

as

(

select dc.State as State, SUM(purchase_price) as TotalPurchase from dwpurchases dp, dwcustomer dc where dp.customer_key = dc.customer_key and dc.country = 'Australia' group by dc.state

),tmpFinal

As

(

select  State, DENSE_RANK() over (order by TotalPurchase) from tmpSum

)select State from tmpFinal where State = 2;

I hope u understood the way of implemention.

Enjoy.

June 2, 2008 5:07 AM
 

Manoj said:

Hi folks,

For finding nth highest value  Try this for irrespective of Database , this should work

For finding nth highest value:

Select max(Column_name) from TempTable T1

where n=(Select count(distinct(Column_name) from TempTable T2 where T1.Column_name <= T2.Column_name)

June 13, 2008 4:49 AM
 

Zolpidem. said:

Zolpidem and sleepwalking. Zolpidem.

June 28, 2008 1:07 AM

Leave a Comment

(required)  
(optional)
(required)  
Add


StopGlobalWarming.org  
Powered by Community Server (Non-Commercial Edition), by Telligent Systems