SQL query in Oracle and SQL server to get 3rd highest salary - sql

In oracle will the below query works for getting 3rd highest salary.
select empname, salary
from (select empname,salary from employee order by salary desc)
where rownum==3
I have seen answers in other threads but they seem to be complicated. If above query works then it is simple solution for oracle
What will be the query for SQLServer?
I don't have Oracle and SQLServer software to try out these queries.
Please let me know

For SQL server the solution would be like this:
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

Use Dense_Rank() ranking function in SQL SERVER to find the 3rd highest salary.
Row_number() returns the sequential number of a row within a partition of a result set, starting at 1 for the first row in each partition.The ORDER BY clause determines the sequence in which the rows are assigned their unique ROW_NUMBER
SELECT empname,
salary
FROM (SELECT Dense_Rank() OVER(ORDER BY salary DESC) rn,
empname,
salary
FROM employee) A
WHERE rn = 3

I did some exploration and found below link which explains the difference between row_number(), rank() and dense_rank(). From the below link I found dense_rank() is suitable answer for this question.
http://www.dwbiconcepts.com/tutorial/24-interview-questions/190-top-20-sql-interview-questions-with-answers.html
row_number() does not give expected results if two or more empolyees has same salary.
Below query works for both Oracle and SQL Server when tried on http://sqlfiddle.com/. The following query gives you the list of employees with third highest salary
SELECT empname, salary FROM (SELECT empname, salary, dense_rank() over(order by salary desc) dense_rank_by_sal
FROM EMPLOYEE ) A where dense_rank_by_sal=3;

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.

nth highest salary using subquery and dense_rank doesn't match when table has duplicate salaries

I was trying to get nth highest salary from table using subquery and dense_rank method.
below are the results for each method.
Subquery Method:
select Top 1 Salary
from (
select top 7 Salary from Employee order by Salary desc
) as Result
order by Salary
This method returns 7th highest salary as: 3000
Dense_Rank Method:
select *
from (
select Salary, DENSE_RANK() Over(order by Salary desc) DRank
from Employee
) as Result
where DRank=7
This method returns 7th highest salary as: 1000
Initial Table data:
Can anyone give me an idea about which method is correct and why?
DENSE_RANK() does not do what you want. It assigns incremental numbers while giving the same rank to ties. So there could be more than 6 records with a higher salary than the records ranked 7th.
The other query gives you the correct result, but could be simplified by using the OFFSET/FETCH syntax, which is available in SQL Server since version 2012:
select * from employee order by salary offset 6 rows fetch next 1 row only

SQL Query with two WHERE conditions

My task is:
To make a query which will get Employees, who earn the biggest salary for their working experience. In other words, the Employee who earns the biggest salary with the biggest experience.
As I consider, I need to make a query with two conditions:
select * from employee where salary in (select max(salary) from employee) and
hire_date in (select min(hire_date) from employee)
I think this was what you're trying to do:
select * from (
select *,
datediff(day,hire_date,getdate()) [Days_Worked],
dense_Rank() over(Partition by datediff(day,hire_date,getdate()) order by salary desc) [RN]
from employee
)a
where a.RN = 1
order by Days_Worked DESC
So that'll give you a list of employees with the highest salary against the employees that have worked the same number of days.
Just note that with dense rank if for example there are 2 employees that have worked 88 days and both earn $50000 (higher than anyone else) it will list both employees, use ROW_NUMBER() instead of DENSE_RANK() if you want to restrict examples like that to 1 employee.
If I get it correctly, this query solves your problem.
SELECT TOP 1 WITH TIES * FROM
employee
ORDER BY
hire_date ASC,
salary DESC

Select Top # in Presto SQL?

Does Presto SQL really lack TOP X functionality in SELECT statements?
If so, is there a workaround in the meantime?
https://prestodb.io/
If you simply want to limit the number of rows in the result set, you can use LIMIT, with or without ORDER BY:
SELECT department, salary
FROM employees
ORDER BY salary DESC
LIMIT 10
If you want the top values per group, you can use the standard SQL row_number() window function. For example, to get the top 3 employees per department by salary:
SELECT department, salary
FROM (
SELECT department, salary row_number() OVER (
PARTITION BY department
ORDER BY salary DESC) AS rn
FROM employees
)
WHERE rn <= 3

How to find out 2nd highest salary of employees?

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 )