How to find out 2nd highest salary of employees? - sql

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 )

Related

Row_number function using directly

Is there any direct way of using row_number() function? I want to find 2 nd highest salary
SELECT DISTINCT id
,salary
,depid
,ROW_NUMBER() OVER (
PARTITION BY depid ORDER BY salary DESC
) AS rownum
FROM emp
WHERE rownum = 2;
It gives an error, However the below code works fine.
SELECT *
FROM (
SELECT DISTINCT id
,salary
,depid
,ROW_NUMBER() OVER (
PARTITION BY depid ORDER BY salary DESC
) AS rownum
FROM emp
) AS t
WHERE t.rownum = 2;
Is any way of directly using the row_number() function as in the first option which is giving the error?
You can not use the alias name of the same query as the condition for the where clause. You also can not use windowed queries as a passing condition in the where clause.
Here is a detailed explanation Why no windowed functions in where clauses?. It is so you need another query outside the inner query and needs to write sub-query.
You can get the Nth highest salary in SQL Server from the below query.
SELECT TOP 1 salary
FROM (
SELECT DISTINCT TOP N salary
FROM <YourTableNameHere>
ORDER BY salary DESC
) AS TEMP
ORDER BY salary
This query will give you the second highest salary ? No
SELECT id
,salary
,depid
from emp
ORDER BY salary DESC
OFFSET 1 ROWS
FETCH FIRST 1 ROWS ONLY;
Well actually, it will give you the salary that is on the second position when you order the salary's from highest to lowest... So if the highest is 100 and the second highest is 100 then you will get 100 as a result. To conclude this will return a row on the second place depending on the order by clause...
This next query will give you the second highest salary :
SELECT max(id)
, salary
, max(depid)
from emp
group by salary
ORDER BY salary DESC
OFFSET 1 ROWS
FETCH FIRST 1 ROWS ONLY;
But be aware, in case you have two employees from two different departments with the same salary then it will return you the one with the higher id and it will return the higher department id which can be incorrect.
And finally this will give you one employee that has a second largest salary with correct data:
SELECT id
, salary
, depid
from emp
where id = (SELECT max(id)
from emp
group by depid, salary
ORDER BY salary DESC
OFFSET 1 ROWS
FETCH FIRST 1 ROWS ONLY);
First, you want dense_rank(), not row_number() if you want the second highest value -- ties might get in the way otherwise.
You can use an arithmetic trick:
SELECT TOP (1) WITH TIES id, salary, depid
FROM emp
ORDER BY ABS(DENSE_RANK() over (PARTITION BY depid ORDER BY salary DESC) - 2)
The "-2" is an arithmetic trick to put the "second" values highest.
That said, I would stick with the subquery because the intent in clearer.
You could use a variation on the trick that uses a TOP 1 WITH TIES in combination with an ORDER BY ROW_NUMBER
SELECT TOP 1 WITH TIES
id,
salary,
depid
FROM emp
ORDER BY IIF(2 = ROW_NUMBER() OVER (PARTITION BY depid ORDER BY salary DESC), 1, 2)
But this trick does have the disadvantage that you can't sort it by something else.
Well, not unless you wrap it in a sub-query and sort the outer query.
A test on rextester here
I prefer to use dense_rank() instead of row_number() function with CTE (common table expression) for the scenario you have mentioned. CTE is modern, easy to use and have many cool features like it is memory resident, it can be used for DUI operations, it make code easy to understand etc.
To find Nth highest salary, the CTE look like
;with findnthsalary
as
(
select empid, deptid, salary,
dense_rank() over(partition by deptid order by salary desc) salrank
from
Employee
)
select distinct id, deptid, salary
from findnthsalary
where salrank = N
I used dense_rank() because if you use row_number() it will produce the wrong result in case multiple employees have the same salary in the same department.

SQL Query About second Max salary

I want to get 2nd highest salary from Employee table. So please help me to find out. I tried it by using below query.
Select Max(salary) from Employee;
It gives the highest salary from salary column. But I want 2nd highest salary.
select max(sal) from
(select sal,dense_rank() over (order by sal desc) dr from emp) where dr=2;
If salaries like 5000,3000,3000,2000... Dense_rank() will give you the employees having 3000 salary
SELECT MAX(Salary) FROM Employee
WHERE Salary NOT IN (SELECT MAX(Salary) FROM Employee )
This gives you second highest.
Try this
DECLARE #N int
SET #N = 2 -- Change the value here to pick a different salary rank
SELECT Salary
FROM (
SELECT row_number() OVER (ORDER BY Salary DESC) as SalaryRank, Salary
FROM Salaries
) as SalaryCTE
WHERE SalaryRank = #N
Not only 2nd Salary but you can get all your desired highest salaries (like 3rd, 5th) by this query.
select salary from(select rownum rn,salary from
(select distinct(salary) from emp order by salary desc)) x where x.rn in (1,2,3);
Just Replace your desired salary position in place of (1,2,3), like (3,5), so it will give you 3rd and 5th highest salary, like:
select salary from(select rownum rn,salary from
(select distinct(salary) from emp order by salary desc)) x where x.rn in (3,5);
Below is the example
SELECT *
FROM (
SELECT column1,
row_number() over (order by salary desc) as [rownum]
From sal_table
) t
WHERE [rownum] = 2
If there is more than one row with same salary you can use dense_rank instead of row_number()
One more:
SELECT a.salary
FROM employee a
WHERE (:n - 1) = (SELECT COUNT(1)
FROM employee b
WHERE b.salary > a.salary);
Just replace n with the nth highest that you want.

SQL command for finding the second highest salary

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)

How to fetch the nth highest salary from a table without using TOP and sub-query?

Recently in an interview I was asked to write a query where I had to fetch nth highest salary from a table without using TOP and any sub-query ?
I got totally confused as the only way I knew to implement it uses both TOP and sub-query.
Kindly provide its solution.
Thanks in advance.
Try a CTE - Common Table Expression:
WITH Salaries AS
(
SELECT
SalaryAmount, ROW_NUMBER() OVER(ORDER BY SalaryAmount DESC) AS 'RowNum'
FROM
dbo.SalaryTable
)
SELECT
SalaryAmount
FROM
Salaries
WHERE
RowNum <= 5
This gets the top 5 salaries in descending order - you can play with the RowNumn value and basically retrieve any slice from the list of salaries.
There are other ranking functions available in SQL Server that can be used, too - e.g. there's NTILE which will split your results into n groups of equal size (as closely as possible), so you could e.g. create 10 groups like this:
WITH Salaries AS
(
SELECT
SalaryAmount, NTILE(10) OVER(ORDER BY SalaryAmount DESC) AS 'NTile'
FROM
dbo.SalaryTable
)
SELECT
SalaryAmount
FROM
Salaries
WHERE
NTile = 1
This will split your salaries into 10 groups of equal size - and the one with NTile=1 is the "TOP 10%" group of salaries.
;with cte as(
Select salary,
row_number() over (order by salary desc) as rn
from salaries
)
select salary
from cte
where rn=#n
(or use dense_rank in place of row_number if you want the nth highest distinct salary amount)
Select *
From Employee E1
Where
N = (Select Count(Distinct(E2.Salary)) From Employee E2 Where E2.Salary >= E1.Salary)
with cte as(
select VendorId,IncomeDay,IncomeAmount,
Row_Number() over ( order by IncomeAmount desc) as RowNumber
from DailyIncome
)
select * from cte
where RowNumber=2
Display 5th Min Sal Emp Table.
SELECT * FROM (SELECT Dense_Rank () Over (ORDER BY Sal ASC) AS Rnk, Emp.* FROM Emp) WHERE
Rnk=5;
Try this.
SELECT * FROM
(SELECT Salary,
rownum AS roworder
FROM (select distinct Salary from employer)
ORDER BY Salary
)
where roworder = 6
;
It can simply be done as following for second highest-
Select MAX(Salary) from employer where Salary NOT IN(Select MAX(Salary) from employer);
But for Nth highest we have to use CTE(Common Table Expression).
try this. It may very easy to find nth rank items by using CTE
**
with result AS
(
SELECT *,dense_rank() over( order by Salary) as ranks FROM Employee
)
select *from RESULT Where ranks = 2
**
To find the Nth highest salary :
Table name - Emp
emplyee_id salary
1 2000
2 3000
3 5000
4 8000
5 7000
6 2000
7 1000
sql query -> here N is higest salary to be found :
select salary from (select salary from Emp order by salary DESC LIMIT N) AS E order by ASC LIMIT 1;
If there are duplicate entries of
30,000,
23,000,
23,000,
15,000,
14,800
then above selected query will not return correct output.
find correct query as below:
with salaries as
(
select Salary,DENSE_RANK() over (order by salary desc) as 'Dense'
from Table_1
)
select distinct salary from salaries
where dense=3
SELECT salery,name
FROM employ
ORDER BY salery DESC limit 1, OFFSET n
with CTE_name (salary,name)
AS
( row_num() over (order by desc salary) as num from tablename )
select salary, name from CTE_name where num =1;
This will work in oracle
In order to find the Nth highest salary, we are only considering unique salaries.Highest salary means no salary is higher than it, Second highest means only one salary is higher than it, 3rd highest means two salaries are higher than it,similarly,Nth highest salary means N-1 salaries are higher than it.
Well, you can do by using LIMIT keyword, which provides pagination
capability.You can do like below:
SELECT salary FROM Employee ORDER BY salary DESC LIMIT N-1, 1
Ex: 2nd highest salary in MySQL without subquery:
SELECT salary FROM Employee ORDER BY salary DESC LIMIT 1,1
6- ways to write Second Highest salary..**
1.select * from employee order by Salary desc offset 1 rows fetch next 1 row only
2.select max(salary) from Employee where salary<(select max(salary) from Employee)
3.select MAX(Salary) from Employee WHERE Salary NOT IN (select MAX(Salary) from Employee );
4.select max(e1.salary) from Employee e1,Employee e2 where e1.salary
5.with cte as(
SELECT *, ROW_NUMBER() OVER( order by SALARY desc) AS ROWNUM FROM EMPLOYEE as rn)
select *From cte where ROWNUM=2
6.select max(e1.Salary) from Employee e1,Employee e2 where e1.Salary
Correct way to get nth Highest salary using NTILE function.
SELECT DISTINCT SAL INTO #TEMP_A FROM EMPLOYEE
DECLARE #CNT INT
SELECT #CNT=COUNT(1) FROM #TEMP_A
;WITH RES
AS(
SELECT SAL,NTILE(#CNT) OVER (ORDER BY SAL DESC) NTL
FROM #TEMP_A )
SELECT SALFROM RES WHERE NTL=3
DROP TABLE #TEMP_A
salary ---> table name
SELECT salary
FROM salary S1
WHERE 5-1 = (
SELECT COUNT( DISTINCT ( S2.salary ) )
FROM salary S2
WHERE S2.salary > S1.salary );
Highest sal using ms sql server:
select sal from emp where sal=(select max(sal) from emp)
Second highest sal:
select max(sal) from emp where sal not in (select max(sal) from emp)
What if we are required to find Nth highest salary without Row_Number,Rank, Dense Rank and Sub Query?
Hope this below Query Helps out.
select * from [dbo].[Test] order by salary desc
Emp_Id Name Salary Department
4 Neelu 10000 NULL
2 Rohit 4000 HR
3 Amit 3000 OPS
1 Rahul 2000 IT
select B.Salary from TEst B join Test A
on B.Salary<=A.Salary
group by (B.Salary)
having count(B.salary)=2
Result:- 4000, The 2nd Highest.

what is the query to return Name and Salary of employee Having Max Salary

what is the query to return Name and Salary of employee Having Max Salary
SELECT Name, Salary FROM Minions
WHERE Salary = (SELECT Max(Salary) FROM Minions)
Note that this will return more than one row if there is more than one employee who have the same max salary
select name, salary from (select * from salary_table order by salary desc limit 1)
SELECT FirstName, max(salary)
FROM Employees
WHERE salary = (
SELECT max(salary)
FROM employees
)
GROUP BY FirstName
working in SQL SERVER 2012
A couple of proprietary solutions
SELECT TOP 1 [WITH ties] Name, Salary
FROM employee
ORDER BY Salary DESC
SELECT Name, Salary
FROM employee
ORDER BY Salary DESC
LIMIT 1
And a standard one
WITH E AS
(
SELECT Name, Salary,
ROW_NUMBER() OVER (ORDER BY Salary DESC) RN /*Or RANK() for ties*/
FROM employee
)
SELECT Name, Salary FROM E WHERE RN=1
In case there are multiple rows with the same MAX number then you can just limit the number to desired number like this
SELECT Name, Salary FROM Minions
WHERE Salary = (SELECT Max(Salary) FROM Minions) LIMIT 1
Select e.name, e.salary from employee e where
not exists (select salary from employee e1 where e.salary < e1.salary)
This will of course return more than one record if there are multiple people with the max salary.
If you are using an oracle database and only want a single "employee" then:
SELECT MAX( name ) KEEP ( DENSE_RANK LAST ORDER BY salary ASC ) AS name,
MAX( salary ) KEEP ( DENSE_RANK LAST ORDER BY salary ASC ) AS salary
FROM Minions;
SQLFIDDLE
(kudos to Neil N for his table name)
SQL Server has a similar FIRST_VALUE (or LAST_VALUE) analytic function.
PostgreSQL also supports window functions including LAST_VALUE.
These type of queries (grouped operaions) can execute with sub query.
Example
select *from emp where sal=(max(sal)from emp)
Assuming only one employee has maximum salary
SQL Server:
select top 1 name, salary
from employee
order by salary desc
Oracle:
select name, salary
from employee
order by salary desc
limit 1
Above queries scans the table only once unlike other queries using subqueries.