I am trying to solve Leetcode's second highest salary (https://leetcode.com/problems/second-highest-salary/). Here's what I implemented on postgres:
select foo.salary as "SecondHighestSalary"
from
(select salary,
dense_rank() over (order by salary desc) as rank
from Employee) foo
where rank = 2;
But the issue is, I need to return NULL if there are no records with rank = 2.
I then tried
select (case
when count(1) = 0 then NULL
else salary
end
)
from
(select salary,
dense_rank() over (order by salary desc) as rank
from Employee) foo
where rank = 2
group by salary;
But it still returns no records.
How do I output NULL when no records are returned?
The solution doesn't work because there's no row for the case to act on.
You can use coalesce and a sub-select.
Rewriting it as a CTE makes the sub-select more compact.
with ranked_salaries as (
select
salary,
dense_rank() over (order by salary desc) as "rank"
from Employee
)
select
coalesce(
(select salary from ranked_salaries where "rank" = 2),
null
);
Note that this is a simpler and faster approach for this particular problem.
select max(salary)
from Employee
where salary < (select max(salary) from Employee)
If salary is indexed, this should be very fast.
You don't actually need COALESCE, just an outer SELECT:
SELECT (
SELECT salary FROM (
SELECT salary, dense_rank() OVER (ORDER BY salary DESC NULLS LAST) AS rank
FROM employee
) sub
WHERE rank = 2
LIMIT 1
) AS second_highest_salary;
See:
Return a value if no record is found
Be sure to add NULLS LAST if salary can be NULL, or you are in for a surprise. (You'd get the highest salary.) See:
Sort NULL values to the end of a table
And there can be multiple rows with rank = 2, so add LIMIT 1.
With an index on salary, Schwern's 2nd query will be substantially faster, though - while dodging the NULL issue because max() excludes NULL values, and dodging the "no row" issue because aggregate functions always return a row, defaulting to NULL in absence of a value.
select max(salary) as "SecondHighestSalary"
from
(select salary,
dense_rank() over (order by salary desc) as rnk
from Employee) foo
where rnk = 2;
Using a dummy aggregate for the output will guarantee a row is returned. It also deals with the potential for tying rows.
I have to get second five (6-10) best salaries records from sorted table using ROWNUM.
Using ROWNUM is necessary.
When I execute query:
SELECT ROWNUM AS position, name, salary
FROM (SELECT name, salary
FROM employees
ORDER BY salary DESC)
WHERE ROWNUM <= 10;
I get a first 10 best records.
And now when I try execute query:
SELECT ROWNUM AS position, name, salary
FROM (SELECT name, salary
FROM employees
ORDER BY salary DESC)
WHERE ROWNUM >= 6 AND ROWNUM <= 10;
I get a empty table. Why doesn't it work?
As explained in the documentation, rownum is evaluated as the rows are fetched. If you never fetch the first row, you never get to the second. Hence, no rows are fetched:
Conditions testing for ROWNUM values greater than a positive integer
are always false. For example, this query returns no rows:
SELECT * FROM employees
WHERE ROWNUM > 1;
But, more importantly, you are using Oracle 12C. So, use fetch first instead of rownum. This has multiple advantages. Besides being standard SQL, you don't need a subquery:
SELECT name, salary
FROM employees
ORDER BY salary DESC
FETCH FIRST 10 ROWS ONLY;
And for your second:
SELECT name, salary
FROM employees
ORDER BY salary DESC
OFFSET 5 ROWS
FETCH FIRST 5 ROWS ONLY;
I write in queston that using ROWNUM is necessary, because it's
academic task.
In such a case use a subquery
SELECT name, salary
FROM (
SELECT name, salary, ROWNUM as my_rownum
FROM employees
ORDER BY salary DESC
)
WHERE my_rownum BETWEEN 6 AND 10
You can use below query and try....
SELECT name,salary from
( SELECT name,salary, DENSE_RANK() OVER (ORDER BY salary DESC) as rn
from employees )
where rn between 6 and 10;
Created table named geosalary with columns name, id, and salary:
name id salary
patrik 2 1000
frank 2 2000
chinmon 3 1300
paddy 3 1700
I tried this below code to find 2nd highest salary:
SELECT salary
FROM (SELECT salary, DENSE_RANK() OVER(ORDER BY SALARY) AS DENSE_RANK FROM geosalary)
WHERE DENSE_RANK = 2;
However, getting this error message:
ERROR: subquery in FROM must have an alias
SQL state: 42601
Hint: For example, FROM (SELECT ...) [AS] foo.
Character: 24
What's wrong with my code?
I think the error message is pretty clear: your sub-select needs an alias.
SELECT t.salary
FROM (
SELECT salary,
DENSE_RANK() OVER (ORDER BY SALARY DESC) AS DENSE_RANK
FROM geosalary
) as t --- this alias is missing
WHERE t.dense_rank = 2
The error message is pretty obvious: You need to supply an alias for the subquery.
Here is a simpler / faster alternative:
SELECT DISTINCT salary
FROM geosalary
ORDER BY salary DESC NULLS LAST
OFFSET 1
LIMIT 1;
This finds the "2nd highest salary" (1 row), as opposed to other queries that find all employees with the 2nd highest salary (1-n rows).
I added NULLS LAST, as NULL values typically shouldn't rank first for this purpose. See:
PostgreSQL sort by datetime asc, null first?
SELECT department_id, salary, RANK1 FROM (
SELECT department_id,
salary,
DENSE_RANK ()
OVER (PARTITION BY department_id ORDER BY SALARY DESC)
AS rank1
FROM employees) result
WHERE rank1 = 3
This above query will get you the 3rd highest salary in the individual department. If you want regardless of the department, then just remove PARTITION BY department_id
Your SQL engine doesn't know the "salary" column of which table you are using, that's why you need to use an alias to differentiate the two columns.
Try this:
SELECT salary
FROM (SELECT G.salary ,DENSE_RANK() OVER(ORDER BY G.SALARY) AS DENSE_RANK FROM geosalary G)
WHERE DENSE_RANK=2;
WITH salaries AS (SELECT salary, DENSE_RANK() OVER(ORDER BY SALARY) AS DENSE_RANK FROM geosalary)
SELECT * FROM salaries WHERE DENSE_RANK=2;
select level, max(salary)
from geosalary
where level=2
connect by
prior salary>salary
group by level;
In case of duplicates in salary column below query will give the right result:
WITH tmp_tbl AS
(SELECT salary,
DENSE_RANK() OVER (ORDER BY SALARY) AS DENSE_RANK
FROM geosalary
)
SELECT salary
FROM tmp_tbl
WHERE dense_rank =
(SELECT MAX(dense_rank)-1 FROM tmp_tbl
)
AND rownum=1;
Here is SQL standard
SELECT name, salary
FROM geosalary
ORDER BY salary desc
OFFSET 1 ROW
FETCH FIRST 1 ROW ONLY
To calculate nth highest salary change offset value
SELECT MAX(salary) FROM geosalary WHERE salary < ( SELECT MAX(salary) FROM geosalary )
How to find third or nth maximum salary from salary table(EmpID, EmpName, EmpSalary) in optimized way?
Row Number :
SELECT Salary,EmpName
FROM
(
SELECT Salary,EmpName,ROW_NUMBER() OVER(ORDER BY Salary) As RowNum
FROM EMPLOYEE
) As A
WHERE A.RowNum IN (2,3)
Sub Query :
SELECT *
FROM Employee Emp1
WHERE (N-1) = (
SELECT COUNT(DISTINCT(Emp2.Salary))
FROM Employee Emp2
WHERE Emp2.Salary > Emp1.Salary
)
Top Keyword :
SELECT TOP 1 salary
FROM (
SELECT DISTINCT TOP n salary
FROM employee
ORDER BY salary DESC
) a
ORDER BY salary
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
Try this
SELECT TOP 1 salary FROM (
SELECT TOP 3 salary
FROM employees
ORDER BY salary DESC) AS emp
ORDER BY salary ASC
For 3 you can replace any value...
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)
Too simple if you use the sub query!
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.
Replace N with your Max Number
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.
And Source
Third or nth maximum salary from salary table without using subquery
select salary from salary
ORDER BY salary DESC
OFFSET N-1 ROWS
FETCH NEXT 1 ROWS ONLY
For 3rd highest salary put 2 in place of N-1
SELECT Salary,EmpName
FROM
(
SELECT Salary,EmpName,DENSE_RANK() OVER(ORDER BY Salary DESC) Rno from EMPLOYEE
) tbl
WHERE Rno=3
SELECT EmpSalary
FROM salary_table
GROUP BY EmpSalary
ORDER BY EmpSalary DESC LIMIT n-1, 1;
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.
Method 1:
SELECT TOP 1 salary FROM (
SELECT TOP 3 salary
FROM employees
ORDER BY salary DESC) AS emp
ORDER BY salary ASC
Method 2:
Select EmpName,salary from
(
select EmpName,salary ,Row_Number() over(order by salary desc) as rowid
from EmpTbl)
as a where rowid=3
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().
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.
declare #maxNthSal as nvarchar(20)
SELECT TOP 3 #maxNthSal=GRN_NAME FROM GRN_HDR ORDER BY GRN_NAME DESC
print #maxNthSal
To get third highest value from table
SELECT * FROM tableName ORDER BY columnName DESC LIMIT 2, 1
This is one of the popular question in any SQL interview. I am going to write down different queries to find out the nth highest value of a column.
I have created a table named “Emloyee” by running the below script.
CREATE TABLE Employee([Eid] [float] NULL,[Ename] [nvarchar](255) NULL,[Basic_Sal] [float] NULL)
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
Select TOP 1 Salary as '3rd Highest Salary' from (SELECT DISTINCT TOP 3 Salary from Employee ORDER BY Salary DESC) a ORDER BY Salary ASC;
I am showing 3rd highest salary
SELECT MIN(COLUMN_NAME)
FROM (
SELECT DISTINCT TOP 3 COLUMN_NAME
FROM TABLE_NAME
ORDER BY
COLUMN_NAME DESC
) AS 'COLUMN_NAME'
--nth highest salary
select *
from (select lstName, salary, row_number() over( order by salary desc) as rn
from employee) tmp
where rn = 2
--(nth -1) highest salary
select *
from employee e1
where 1 = (select count(distinct salary)
from employee e2
where e2.Salary > e1.Salary )
Optimized way: Instead of subquery just use limit.
select distinct salary from employee order by salary desc limit nth, 1;
See limit syntax here http://www.mysqltutorial.org/mysql-limit.aspx
By subquery:
SELECT salary from
(SELECT rownum ID, EmpSalary salary from
(SELECT DISTINCT EmpSalary from salary_table order by EmpSalary DESC)
where ID = nth)
Try this Query
SELECT DISTINCT salary
FROM emp E WHERE
&no =(SELECT COUNT(DISTINCT salary)
FROM emp WHERE E.salary <= salary)
Put n= which value you want
set #n = $n
SELECT a.* FROM ( select a.* , #rn = #rn+1 from EMPLOYEE order by a.EmpSalary desc ) As a where rn = #n
MySQL tested solution, assume N = 4:
select min(CustomerID) from (SELECT distinct CustomerID FROM Customers order by CustomerID desc LIMIT 4) as A;
Another example:
select min(country) from (SELECT distinct country FROM Customers order by country desc limit 3);
Try this code :-
SELECT *
FROM one one1
WHERE ( n ) = ( SELECT COUNT( one2.salary )
FROM one one2
WHERE one2.salary >= one1.salary
)
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
In SQL Server 2012+, OFFSET...FETCH would be an efficient way to achieve this:
DECLARE #N AS INT;
SET #N = 3;
SELECT
EmpSalary
FROM
dbo.Salary
ORDER BY
EmpSalary DESC
OFFSET (#N-1) ROWS
FETCH NEXT 1 ROWS ONLY
select * from employee order by salary desc;
+------+------+------+-----------+
| id | name | age | salary |
+------+------+------+-----------+
| 5 | AJ | 20 | 100000.00 |
| 4 | Ajay | 25 | 80000.00 |
| 2 | ASM | 28 | 50000.00 |
| 3 | AM | 22 | 50000.00 |
| 1 | AJ | 24 | 30000.00 |
| 6 | Riu | 20 | 20000.00 |
+------+------+------+-----------+
select distinct salary from employee e1 where (n) = (select count( distinct(salary) ) from employee e2 where e1.salary<=e2.salary);
Replace n with the nth highest salary as number.
SELECT TOP 1 salary FROM ( SELECT TOP n salary FROM employees ORDER BY salary DESC Group By salary ) AS emp ORDER BY salary ASC
(where n for nth maximum salary)
Just change the inner query value: E.g Select Top (2)* from Student_Info order by ClassID desc
Use for both problem:
Select Top (1)* from
(
Select Top (1)* from Student_Info order by ClassID desc
) as wsdwe
order by ClassID
HI,
Can u tell me the syntax of the SQL command which gives as output the second highest salary from a range of salaries stored in the employee table.
A description of the SQL commnd will be welcomed...
Please help!!!
select min(salary) from
(select top 2 salary from SalariesTable order by salary desc)
as ax
This should work:
select * from (
select t.*, dense_rank() over (order by salary desc) rnk from employee t
) a
where rnk = 2;
This returns the second highest salary.
dense_rank() over is a window function, and it gives you the rank of a specific row within the specified set. It is standard SQL, as defined in SQL:2003.
Window functions are awesome in general, they simplyfy lots of difficult queries.
Slightly different solution:
This is identical except that returns the highest salary when there is a tie for number 1:
select * from (
select t.*, row_number() over (order by salary desc) rnk from employee t
) a
where rnk = 2;
Updated: Changed rank to dense_rank and added second solution. Thanks, IanC!
with tempTable as(
select top 2 max(salary) as MaxSalary from employee order by salary desc
) select top 1 MaxSalary from tempTable
description:
select the top 2 maximum salaries
order them by desc order ( so the 2nd highest salary is now at the top)
select the top 1 from that
another approach:
select top 1 MaxSalary from (
select top 2 max(salary) as MaxSalary from employee order by salary desc
)
Here's some sample code, with proof of concept:
declare #t table (
Salary int
)
insert into #t values (100)
insert into #t values (900)
insert into #t values (900)
insert into #t values (400)
insert into #t values (300)
insert into #t values (200)
;WITH tbl AS (
select t.Salary, DENSE_RANK() OVER (order by t.Salary DESC) AS Rnk
from #t AS t
)
SELECT *
FROM tbl
WHERE Rnk = 2
DENSE_RANK is mandatory (change to RANK & you'll see).
You'll also see why any SELECT TOP 2 queries won't work (without a DISTINCT anyway).
You don't specify the actual SQL product you're using, and the query language varies among products. However, something like this should get you started:
SELECT salary FROM employees E1
WHERE 1 = (SELECT COUNT(*) FROM employee E2 WHERE E2.salary > E1.salary)
(thanks to fredt for the correction).
Alternatively (and faster in terms of performance) would be
SELECT TOP 2 salary FROM employees ORDER BY salary DESC
and then skipping the first returned row.
An alternative (tested):
select Min(Salary) from (
select distinct TOP (2) salary from employees order by salary DESC) AS T
This will work on any platform, is clean, and caters for the possibility of multiple tied #1 salaries.
Select top 1 * from employee where empID in (select top 2 (empID) from employee order by salary DESC) ORDER BY salary ASC
Explanation:
select top 2 (empID) from employee order by salary DESC would give the two records for which Salary is top and then the whole query would sort it these two records in ASCENDING order and then list out the one with the lowest salary among the two.
EX. let the salaries of employees be 100, 99, 98,,50.
Query 1 would return the emp ID of the persons with sal 100 and 99
Whole query would return all data related to the person having salary 99.
SELECT Salary,EmpName
FROM
(
SELECT Salary,EmpName,ROW_NUMBER() OVER(ORDER BY Salary) As Rank
FROM EMPLOYEE
) A
WHERE A.Rank=n;
where n is the number of highest salary u r requesting the table.
Ucan also use DenseRank() function in place of ROW_NUMBER().
Thanks,
Suresh
An easier way..
select MAX(salary) as SecondMax from test where salary !=(select MAX(salary) from test)