Using dense_rank to find the 2nd highest salary in MYSQL - mysql

I am trying to do this Leetcode question where we try to find the 2nd highest salary from the EMPLOYEE TABLE.
INPUT :
+-------------+------+
| Column Name | Type |
+-------------+------+
| id | int |
| salary | int |
+-------------+------+
id is the primary key column for this table.
Each row of this table contains information about the salary of an employee.
My answer is the following. But leetcode is not accepting this answer. What if I don't want to use the offset clause and use the dense function? Can it be done? Kindly help.
with temp1 as
(select id, salary, dense_rank() over (order by salary desc) as salary_order
from employee)
select coalesce(salary, null) as SecondHighestSalary
from temp1
where salary_order=2;
Question Link: https://leetcode.com/problems/second-highest-salary/

DENSE_RANK() is fine for this problem, but if you filter the cte and there is no 2nd highest salary, the query will not return null.
Also, coalesce(salary, null) would just return null if salary is already null, so it does not help.
With conditional aggregation you can get the 2nd highest salary and null if it does not exist:
WITH cte AS (SELECT salary, DENSE_RANK() OVER (ORDER BY salary DESC) AS salary_order FROM employee)
SELECT MAX(CASE WHEN salary_order = 2 THEN salary END) AS SecondHighestSalary
FROM cte;
See the demo.

Related

SQL CASE WHEN won't meet condition

select salary as SecondHighestSalary
from Employee
where salary = case
when (select count(*)
from Employee) <= 1 then null
when (
select count(*)
from Employee
) > 1 then (
select salary
from (select salary
from Employee
order by salary desc
limit 2
) as two_highest_salary_table
order by salary asc
limit 1
)
end;
This is a solution to one of the leetcode problem. It is asking me to output the second highest salary from the table and if there are no second highest salary then the output should be null.
The above is my solution. I used case and when syntax but the problem is that even when the table only has 1 row, it doesn't output a table with a NULL value but it just output a table w nothing in it.
How can I fix this problem?
It is much simpler, as you thought, a simole SELECT with LOT and OFFSET is enough
CREATE TABLE Employee (salary DECIMAL(10,2))
INSERT INTO Employee VALUES(10000.1)
select salary
from Employee
order by salary desc
limit 1,2
| salary |
| -----: |
INSERT INTO Employee VALUES(20000.2)
select salary
from Employee
order by salary desc
limit 1,2
| salary |
| -------: |
| 10000.10 |
db<>fiddle here
I think you are complicating a little.
Try :
SELECT MAX(Salary) as Salary
From Employee1
WHERE Salary < ( SELECT Max(Salary) FROM Employee1);
Demo
If you need to always return a row with NULL if there's no qualifying second-highest value you need to outer join to a source row - this will allow you to return all columns if required.
select Salary
from
(select 2 as s) choice
left join (
select salary, dense_rank() over(order by salary desc) rnk
from Employee
)s on s.rnk = s;
Example Fiddle

SQL Case When not labeling null

I'm trying to do this Leet Code Problem:
Write a SQL query to get the second highest salary from the Employee table.
+----+--------+
| Id | Salary |
+----+--------+
| 1 | 100 |
| 2 | 200 |
| 3 | 300 |
+----+--------+
For example, given the above Employee table, the query should return 200 as the second highest salary. If there is no second highest salary, then the query should return null.
+---------------------+
| SecondHighestSalary |
+---------------------+
| 200 |
+---------------------+
I'm trying to give this solution:
SELECT
CASE WHEN Salary = ''
THEN NULL
ELSE Salary END SecondHighestSalary
FROM
Employee
ORDER BY
SecondHighestSalary
LIMIT 1,1;
When there is a second salary, it works fine and returns the output. However, when there is no second salary and there's only one salary only an empty string is returned. I'm trying to return NULL, however, it doesn't return NULL like what I wrote in my query. How can I fix this?
Your CASE expression is testing the salary in each row of the table, not the one selected by the LIMIT clause. Ordering is done after generating the values in the SELECT list, since you can order by those calculated values.
Since none of the salaries are empty strings, the condition in your CASE will never be true, so it always returns the Salary value. As a result, your query is equivalent to
SELECT Salary AS SecondHighestSalary
FROM Employee
ORDER BY SecondHighestSalary
LIMIT 1, 1
Other things:
You need to use DESC to get the highest salary at the beginning. So even if your method worked, it would find the second lowest salary.
Your method doesn't handle the case where multiple employees are tied for the highest salary. LIMIT 1, 1 will return the second row, which will be one of the tied employees.
You can solve the second problem using a subquery that removes duplicates:
SELECT DISTINCT Salary
FROM Employee
So a final query could be:
SELECT IF(COUNT(*) > 0, MAX(Salary), NULL) AS SecondHighestSalary
FROM (
SELECT DISTINCT Salary
FROM Employee
ORDER BY Salary DESC
LIMIT 1, 1
) AS x
You can use this solution, where if there have no second highest salary will return NULL. Otherwise will return second highest salary
SELECT
IFNULL(MIN(Salary) , 'NULL') as SecondHighestSalary
FROM
Employee
WHERE salary > (SELECT MIN(salary)
FROM Employee)
Or if you want DB default null then just remove IFNULL condition
SELECT
MIN(Salary) as SecondHighestSalary
FROM
Employee
WHERE salary > (SELECT MIN(salary)
FROM Employee)
E.g.
select max(salary) salary
from employee
where salary not in
(select max(salary) from employee)

to get nth highest salary from a table there is a code which i dont understand

first of all i cant understand how a.salary <= b.salary internally works. if worker a and worker b are clones then how is >= computed internally and if the sign is changed to <,>,= HOW is it working?
COUNT(distinct salary) should just give a number so if there are 3 distinct salaries there should be value 3 for it. if I execute it without the 'where' condition then it does'nt show any result.
how does the 'where 1=' actually work? it shows different result for 2>=,3>= etc.
there are other methods to find the nth highest salary but i need to understand this one
select distinct salary
from worker a
where 1 = (select COUNT(distinct salary) from worker b where a.salary >= b.salary)
Consider this table:
create table worker(name varchar(10), salary int);
insert into worker(name, salary) values
('Alice', 500),('Bob', 400),('John', 500),('Nick', 400),('Mary', 300),('Jill', 300);
And these queries with the corresponding results:
select count(distinct salary) counter from worker where salary >= 500
| counter |
| 1 |
select count(distinct salary) counter from worker where salary >= 400
| counter |
| 2 |
select count(distinct salary) counter from worker where salary >= 300
| counter |
| 3 |
What these queries do is return the number of distinct salaries that are greater or equal than a certain amount.
So if there is a salary = 500 since the result of the 1st query is 1 this means that there isn't any salary greater than this, so this is the max salary because the number of distinct salaries that are greater or equal to that salary is 1.
The 2nd query's result is 2 and this means that there is only 1 distinct salary greater than 400, so this the 2nd greater salary of all.
Now consider the same queries with the reverse inequality sign:
select count(distinct salary) counter from worker where 300 >= salary
| counter |
| 1 |
select count(distinct salary) counter from worker where 400 >= salary
| counter |
| 2 |
select count(distinct salary) counter from worker where 500 >= salary
| counter |
| 3 |
the 1st query returns the minimum salary because the number of distinct salaries that are less or equal than 300 is 1, and so on.
This is what your code does: it finds the minimum and not the maximum salary.
If you want the max salary you must write the code like this:
select distinct salary
from worker a
where 1 = (select COUNT(distinct salary) from worker b where b.salary >= a.salary)
If you want the 2nd highest salary you must write the code like this:
select distinct salary
from worker a
where 2 = (select COUNT(distinct salary) from worker b where b.salary >= a.salary)
See the demo.

Find second highest highest query doesn't work

I could not figure out why my query does not work. The errors shows aggregate function have to use group by. I add "group by MAX(Salary)" which can not do the trick. Please help, thanks!
Table:
Query
SELECT Name, MAX(Salary)
FROM PRACTICE.SALARY
WHERE Salary
NOT IN (SELECT MAX(Salary) FROM PRACTICE.SALARY);
When you use aggregate function you need to add non-aggregate columns in group by
SELECT Name, MAX(Salary)
FROM PRACTICE.SALARY
WHERE Salary
NOT IN (SELECT MAX(Salary) FROM PRACTICE.SALARY)
GROUP BY Name
but If you only want to get second heigh SALARY, your query will get the wrong result because you group by for each NAME and get MAX(Salary) will get every Salary of Max from each NAME instead of the whole table.
I think you can use this query to get your expect result.
Schema (MySQL v5.7)
CREATE TABLE T(
Name VARCHAR(50),
Salary int
);
INSERT INTO T VALUES ('Lucy',2008);
INSERT INTO T VALUES ('PETER',3000);
INSERT INTO T VALUES ('K',1900);
INSERT INTO T VALUES ('TOM',2015);
INSERT INTO T VALUES ('MARK',3001);
Query #1
SELECT Name, Salary
FROM PRACTICE.SALARY
WHERE Salary <> (SELECT MAX(Salary) FROM PRACTICE.SALARY)
ORDER BY Salary DESC
LIMIT 1;
| Name | Salary |
| ----- | ------ |
| PETER | 3000 |
View on DB Fiddle

SQL query to find Nth highest salary from a salary table

some one help me to find out nth highest salary from the salary table in MYSQL
Try this, n would be the nth item you would want to return
SELECT DISTINCT(Salary) FROM table ORDER BY Salary DESC LIMIT n,1
If you want to find nth Salary from a table (here n should be any thing like 1st or 2nd or 15th highest Salaries)
This is the Query for to find nth Salary:
SELECT DISTINCT Salary FROM tblemployee ORDER BY Salary DESC LIMIT 1 OFFSET (n-1)
If you want to find 8th highest salary, query should be :
SELECT DISTINCT Salary FROM tblemployee ORDER BY Salary DESC LIMIT 1 OFFSET 7
Note: OFFSET starts from 0th position, and hence use N-1 rule here
To get nth highest salary you need to first sort data by using ORDER BY and then select the nth highest record using LIMIT with OFFSET.
SELECT DISTINCT(salary) AS salary
FROM tbl_salary
ORDER BY salary DESC
LIMIT 1 OFFSET (n - 1);
SELECT * FROM Employee Emp1
WHERE (N-1) = (
SELECT COUNT(DISTINCT(Emp2.Salary))
FROM Employee Emp2
WHERE Emp2.Salary > Emp1.Salary)
For each record processed by outer query, inner query will be executed and will return how many records has records has salary less than the current salary. If you are looking for second highest salary then your query will stop as soon as inner query will return N-1.
finding the highest salary
select MAX(Salary) from Employee;
finding the 2nd highest salary
Query-1
SELECT MAX(Salary) FROM Employee
WHERE Salary NOT IN (SELECT MAX(Salary) FROM Employee);
Query-2
select MAX(Salary) from Employee
WHERE Salary <> (select MAX(Salary) from Employee )
finding the nth highest salary
Query-1
SELECT * /*This is the outer query part */
FROM Employee Emp1
WHERE (N-1) = ( /* Subquery starts here */
SELECT COUNT(DISTINCT(Emp2.Salary))
FROM Employee Emp2
WHERE Emp2.Salary > Emp1.Salary)
Query-2
SELECT *
FROM Employee Emp1
WHERE (1) = (
SELECT COUNT(DISTINCT(Emp2.Salary))
FROM Employee Emp2
WHERE Emp2.Salary > Emp1.Salary)
nth highest salary using the TOP keyword in SQL Server
SELECT TOP 1 Salary
FROM (
SELECT DISTINCT TOP N Salary
FROM Employee
ORDER BY Salary DESC
) AS Emp
ORDER BY Salary
Find the nth highest salary in MySQL
SELECT Salary FROM Employee
ORDER BY Salary DESC LIMIT n-1,1
Find the nth highest salary in SQL Server
SELECT Salary FROM Employee
ORDER BY Salary DESC OFFSET N-1 ROW(S)
FETCH FIRST ROW ONLY
Find the nth highest salary in Oracle using rownum
select * from (
select Emp.*,
row_number() over (order by Salary DESC) rownumb
from Employee Emp
)
where rownumb = n; /*n is nth highest salary*/
Find the nth highest salary in Oracle using RANK
select * FROM (
select EmployeeID, Salary
,rank() over (order by Salary DESC) ranking
from Employee
)
WHERE ranking = N;
Here we can create the MYSQL function for this.
nth highest salary from the Employee table.
+----+--------+
| Id | Salary |
+----+--------+
| 1 | 100 |
| 2 | 200 |
| 3 | 300 |
+----+--------+
For example, given the above Employee table, the nth highest salary where n = 2 is 200. If there is no nth highest salary, then the query should return null.
CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGIN
DECLARE limitv INT;
SET limitv = N - 1;
RETURN (
Select IFNULL(
(select Distinct Salary from Employee order by Salary Desc limit limitv, 1),
NULL
) as getNthHighestSalary
);
END
try this:
select MIN(sal) from salary where sal in
(select sal from salary order by sal desc limit 9)
if wanna specified nth highest,could use rank method.
To get the third highest, use
SELECT * FROM
(SELECT #rank := #rank + 1 AS rank, salary
FROM tbl,(SELECT #rank := 0) r
order by salary desc ) m
WHERE rank=3
Try this one for finding 5th highest salary-
SELECT DISTINCT(column name) FROM table ORDER BY (column name) desc LIMIT 4,1
for nth salary-
SELECT DISTINCT(column name) FROM table ORDER BY (column name) desc LIMIT n-1,1
I have tried it on phpmyadmin panel..
+-------+--------+
| name | salary |
+-------+--------+
| A | 100 |
| B | 200 |
| C | 300 |
| D | 400 |
| E | 500 |
| F | 500 |
| G | 600 |
+-------+--------+
IF YOU WANT TO SELECT ONLY Nth HIGHEST SALARY THEN:
SELECT DISTINCT salary FROM emp ORDER BY salary DESC LIMIT 1 OFFSET N-1;
IF YOU WANT TO SELECT ALL EMPLOYEE WHO GETTING Nth HIGHEST SALARY THEN:
SELECT * FROM emp WHERE salary = (
SELECT DISTINCT salary FROM emp ORDER BY salary DESC LIMIT 1 OFFSET N-1
);
SELECT * FROM employe e1 WHERE n-1 = ( SELECT COUNT(DISTINCT(e2.salary)) FROM employe e2 WHERE e2.salary > e1.salary)
Where n = highest number of salary like 1,2,3
Sorting all the records first, do consume a lot of time (Imagine if the table contains millions of records).
However, the trick is to do an improved linear-search.
SELECT * FROM Employee Emp1
WHERE (N-1) = ( SELECT COUNT(*) FROM (
SELECT DISTINCT(Emp2.Salary)
FROM Employee Emp2
WHERE Emp2.Salary > Emp1.Salary LIMIT N))
Here, as soon as inner query finds n distinct salary values greater than outer query's salary, it returns the result to outer query.
Mysql have clearly mentioned about this optimization at http://dev.mysql.com/doc/refman/5.6/en/limit-optimization.html
The above query can also be written as,
SELECT * FROM Employee Emp1
WHERE (N-1) = (
SELECT COUNT(DISTINCT(Emp2.Salary))
FROM Employee Emp2
WHERE Emp2.Salary > Emp1.Salary LIMIT N)
Again, if the queries are as simple as just running on single table and needed for informational purposes only, then you could limit the outermost query to return 1 record and run a separate query by placing the nth highest salary in where clause
Thanks to Abishek Kulkarni's solution, on which this optimization is suggested.
select distinct(column_name) from table_name order by column_name desc limit (n-1),1;
MySQL query to find Nth highest salary from a salary table(100% true)
SELECT Salary FROM Employee ORDER BY Salary DESC LIMIT N-1,1;
SELECT DISTINCT(column_name)
FROM table_name
ORDER BY column_name DESC limit N-1,1;
where N represents the nth highest salary ..
Third highest salary :
SELECT DISTINCT(column_name)
FROM table_name
ORDER BY column_name DESC limit 2,1;
The query to get the nth highest record is as follows:
SELECT
*
FROM
(SELECT
*
FROM
table_name
ORDER BY column_name ASC
LIMIT N) AS tbl
ORDER BY column_name DESC
LIMIT 1;
It's simple and easy to understand
For 4th highest salary:
select min(salary) from (select distinct salary from hibernatepractice.employee e order by salary desc limit 4) as e1;
For n th highest salary:
select min(salary) from (select distinct salary from hibernatepractice.employee e order by salary desc limit n) as e1;
This is salary table
SELECT amount FROM salary
GROUP by amount
ORDER BY amount DESC
LIMIT n-1 , 1
Or
SELECT DISTINCT amount
FROM salary
ORDER BY amount DESC
LIMIT n-1 , 1
This will work To find the nth maximum number
SELECT
TOP 1 * from (SELECT TOP nth_largest_no * FROM Products Order by price desc) ORDER BY price asc;
For Fifth Largest number
SELECT
TOP 1 * from (SELECT TOP 5 * FROM Products Order by price desc) ORDER BY price asc;
set #cnt=0;
select s.* from (SELECT (#cnt := #cnt + 1) AS rank,a.* FROM one as a order by a.salary DESC) as s WHERE s.rank='3';
=>this for 3rd highest salary.
for nth replace 3 value. for example 5th highest:
set #cnt=0;
select s.* from (SELECT (#cnt := #cnt + 1) AS rank,a.* FROM one as a order by a.salary DESC) as s WHERE s.rank='5';
SET #cnt=0;
SELECT s.*
FROM (SELECT ( #cnt := #cnt + 1 ) AS rank,
a.*
FROM one AS a
ORDER BY a.salary DESC) AS s
WHERE s.rank = '3';
To get 2nd highest salary:
SELECT salary
FROM [employees]
ORDER BY salary DESC
offset 1 rows
FETCH next 1 rows only
To get Nth highest salary:
SELECT salary
FROM [employees]
ORDER BY salary DESC
offset **n-1** rows
FETCH next 1 rows only
Try this solution.
select SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(DISTINCT salary ORDER BY salary DESC),',',3),',',-1) from employees
Let there be table salaries containing
+----------+--------+--------+
| emp | salary | deptno |
+----------+--------+--------+
| ep1 | 10 | dp1 |
| ep2 | 20 | dp2 |
| ep3 | 30 | dp2 |
| ep4 | 40 | dp1 |
| ep5 | 50 | dp1 |
| ep6 | 60 | dp3 |
| ep7 | 70 | dp3 |
+----------+--------+--------+
By Nested Queries: (where you can change offset 0/1/2... for first, second and third... place respectively)
select
*
from
salaries as t1
where
t1.salary = (select
salary
from
salaries
where
salaries.deptno = t1.deptno ORDER by salary desc limit 1 offset 1);
or might be by creating rank: (where you can change rank= 1/2/3... for first, second and third... place respectively)
SET #prev_value = NULL;
SET #rank_count = 0;
select * from
(SELECT
s.*,
CASE
WHEN #prev_value = deptno THEN #rank_count := #rank_count + 1
WHEN #prev_value := deptno THEN #rank_count := 1
ELSE #rank_count := 1
END as rank
FROM salaries s
ORDER BY deptno, salary desc) as t
having t.rank = 2;
I have used Procedure for this query
here getHighestSalary procedure, reports the nth highest salary from the Employee table. If there is no nth highest salary, the query should report null.
first, create table
CREATE TABLE employee (
id INT AUTO_INCREMENT,
salary INT,
PRIMARY KEY (id) );
next, create PROCEDURE
DELIMITER //
CREATE PROCEDURE getHighestSalary(emp_id int)
BEGIN
select ifnull((select salary from employee where id = emp_id order by salary desc), null) as getNthHighestSalary;
END //
DELIMITER ;
and last, call the getHighestSalary procedure with n value
call getHighestSalary(2); -- 200
If you want to get all the records of the employees who has third highest salary then you can use this sql query:
Table name: salary
select * from salary where salary =
(select distinct salary from salary order by salary desc limit 2,1)