Find the second highest salary [duplicate] - sql

This question already has answers here:
How to find the employee with the second highest salary?
(5 answers)
Closed 2 years ago.
Well it is a well known question. Consider the below
EmployeeID EmployeeName Department Salary
----------- --------------- --------------- ---------
1 T Cook Finance 40000.00
2 D Michael Finance 25000.00
3 A Smith Finance 25000.00
4 D Adams Finance 15000.00
5 M Williams IT 80000.00
6 D Jones IT 40000.00
7 J Miller IT 50000.00
8 L Lewis IT 50000.00
9 A Anderson Back-Office 25000.00
10 S Martin Back-Office 15000.00
11 J Garcia Back-Office 15000.00
12 T Clerk Back-Office 10000.00
We need to find out the second highest salary
With Cte As
(
Select
level
,Department
,Max(Salary)
From plc2_employees
Where level = 2
Connect By Prior (Salary) > Salary)
Group By level,Department
)
Select
Employeeid
,EmployeeName
,Department
,Salary
From plc2_employees e1
Inner Join Cte e2 On e1.Department = e2.Department
Order By
e1.Department
, e1.Salary desc
,e1.EmployeeID
is somehow not working... I am not getting the correct result. Could anyone please help me out.

Something like
select * from
(
select EmployeeID, EmployeeName, Department, Salary,
rank () over (partition by Department order by Salary desc) r
from PLC2_Employees
)
where r = 2
Edit - tested it and it gives the answer you expected.

If you're going to teach yourself how to deal with CONNECT BY, you should first find a problem that is suited to the construct. CONNECT BY is meant for processing data that's in a hierarchical form, which your example is not. Salaries are not related to each other in a hierarchical fashion. Trying to force-fit a construct on the wrong problem is frustrating and doesn't really teach you anything.
Take a look at the classic employee-manager relationship in the demo HR schema you can install with Oracle. All employees report to a manager, including managers (except the top guy). You can then use this schema to create a query to show, for example, the Organization Chart for the company.

START WITH … CONNECT BY is designed to explore data that forms a graph, by exploring all possible descending paths. You specify the root nodes in the START WITH clause and the node connections in the CONNECT BY clause (not in the WHERE clause).
The WHERE clause filters will be processed after the hierachical conditions, same for GROUP BY and HAVING (of course because GROUP BY is computed after WHERE).
Therefore you MUST here CONNECT BY PRIOR department = department for example. You must also avoid that a node connection is done between two salaries when there is an intermediate salary.
Therefore the final query would resemble this:
SELECT level
, Department
, Salary
FROM plc2_employees pe1
START WITH pe1.salary = (select max(salary) from plc2_employees pe2 WHERE pe2.Department = pe1.Department)
CONNECT BY PRIOR pe1.Department = pe1.Department
AND PRIOR pe1.Salary > pe1.Salary
AND PRIOR pe1.Salary = ( SELECT MIN(Salary) FROM plc2_employees pe3
WHERE pe3.Department = pe1.Department
AND pe3.Salary > pe1.Salary
)
The recursion condition states that there is no intermediate salary between the child row and the parent row.
Note that this will really be unefficient…

Try this, it gives second highest salary
select MAX(Salary) as Salary
from Employee_salary
where Salary not in (select MAX(Salary) from Employee_salary)

You can use this query:
select * from
employee e1
where 2 = (select count (distinct (salary))
from employee e2
where e2.salary >=e1.salary);

find out second highest salary from employee table having column as salary:
Database : DB2
with t as
(
select distinct salary from employee order by salary desc
),
tr as
(
select salary, row_Number() over() r from t
)
select salary from tr where r = 2

Try this,
It gives second highest salary...
select MAX(Salary) as Salary
from Employee_salary
where Salary not in (select MAX(Salary) from Employee_salary )
If you want to find nth highest salary than you can use following query....
you need to do just one change.....
Put the value of N=nth highest
Cheers....:)
SELECT * FROM Employee_salary Emp1
WHERE (N-1) = (SELECT COUNT(DISTINCT(Emp2.Salary))
FROM Employee_salary Emp2
WHERE Emp2.Salary > Emp1.Salary)

This will work -
SELECT MIN(Salary)
FROM employee
WHERE salary IN (SELECT TOP 2 salary FROM employee ORDER BY salary DESC)

First, select the distinct salaries in descending order (from greatest to least), from that set select the top 2 and put in ascending order (placing number 2 on top), then from those 2 select top 1:
select top 1 s.Salary
from
(select top 2 t.Salary
from
(select distinct Salary
from PLC2_Employees
order by Salary desc) t
order by Salary asc) s

Related

Selecting the record(s) with the "second" highest something

I have written the following SQL commands for retrieving data from a table called Employee.
I was able to get the highest/maximum salary as well as the second highest/maximum salary, but I am having difficulty writing the same when the whole record needs to be returned.
Select all the employees.
SELECT * FROM Employee
Return the highest salary. This returns the maximum salary amount which is 90000
SELECT MAX(salary) FROM Employee
Return the employee record with the highest salary. This returns all the records of the person/people with their salary being the maximum salary which is 90000 that is only John Henry in this case.
SELECT *
FROM Employee
WHERE salary = ( SELECT MAX(salary) FROM Employee )
Return every other employee record; i.e. everyone except the one with the highest salary.
SELECT *
FROM Employee
WHERE salary != ( SELECT MAX(salary) FROM Employee )
Return the second highest salary. This returns the second maximum salary amount which is 85000
SELECT MAX(salary) FROM Employee
WHERE salary != ( SELECT MAX(salary) FROM Employee )
Return the employee record with the second highest salary. This returns all the records of the person/people with their salary being the second maximum salary which is 85000 that is only Michael Greenback in this case.
I am stuck in this... I tried using HAVING as an extra condition, but however I arrange it to specify a condition, I get syntax errors. How do I do this?
Window functions are the built-in functionality to do this. In particular, dense_rank():
select e.*
from (select e.*, dense_rank() over (order by salary desc) as seqnum
from employee e
) e
where seqnum = 2;
This is a SQL Server solution but can be easily re-written using limit N instead of top N. If your database doesn't support window functions, you could try this. If it does, Gordon's solution is the way to go.
with cte as
(select max(salary) as second_max
from employee
where salary in (select distinct top 2 salary -- top n is what makes this scalable
from employee
order by salary asc)) -- get top 2 salaries and sort them
select *
from employee
where salary = (select second_max from cte);

Find department with maximum number of employees in Oracle SQL

I have these two tables and I need to find the department name with maximum number of employees.
The other solutions were not for Oracle, so I'm posting this question. Also, it would be really helpful if the query can be explained thoroughly as I'm finding it hard to visualise it.
EMPLOYEE
EMPNO EMPNAME MANAGER SALARY DEPT_NO
1 Puja 6 30000 2
2 Purabi 1 15000 3
3 Barun 6 23000 2
4 Sudha 1 20000 1
5 Amal 2 20000 1
6 Rakesh 3 30000 4
DEPARTMENT
Dept_No Dept_Name Location
1 Production LaneA
2 Marketing LaneB
3 Sales LaneC
4 HR LaneD
So far I could manage getting the highest number of employees. So I was thinking if somehow I can write another sub-query where I count the employees in the departments again and compare them to the max_num_emp that I calculated in the first query.
This is the query which retrieves the maximum number of employees. It does not return the dept_no.
select count(dept_no)
from employee
group by dept_no
order by count(dept_no) desc
fetch first row only;
Expected output
DEPT_NAME
Production
Marketing
I can also add the dept_no column in the query, then I will have to somehow find out how to get the max and that was somehow giving me errors because the query was violating some rules. I had actually tried doing max(above query).
So I thought of just getting the maximum employee count and then determine all departments which have those many employees and display their name.
You have a working query which you need to join to the table department:
select d.Dept_Name
from department d inner join (
select dept_no
from employee
group by dept_no
order by count(*) desc
fetch first row only
) t
on t.dept_no = d.dept_no
Edit
Try this (I cannot try it):
select d.dept_name
from department d inner join (
select x.dept_no from (
select dept_no, rank() over (order by count(*) desc) rn
from employee
group by dept_no
order by count(dept_no) desc
) x
where x.rn = 1
) t
on t.dept_no = d.dept_no
You may have used FETCH..FIRST syntax using WITH TIES instead of ONLY.
SELECT d.dept_name
FROM department d
JOIN employee e ON d.dept_no = e.dept_no
GROUP BY d.dept_name
ORDER BY COUNT(*)
DESC FETCH FIRST 1 ROW WITH TIES ;
Demo
If you are not looking for duplicates, then:
select d.dept_name, count(*)
from department d join
employee e
on d.dept_no = e.dept_no
group by d.dept_no, d.dept_name
order by count(dept_no) desc
fetch first row only;

Highest salary per department (also same salary)

How can I select the highest salary on each department with a same salary.
My query is only to get the first row in each department with the same salary. But I want to select all max same salary on each department. Please help me out of this problem.
Below is the sample table:
PSD Department
----------------------
Yumang's Salary: $500
Paus Salary: $500
QA Department
----------------------
Villanueva: $1000
Calacar: $1000
Here's the code I am trying:
SELECT MAX(inter_department_votes.number_votes)
FROM employee_salary
GROUP BY dept_id
try selecting dept_id as well:
SELECT dept_id,
MAX(inter_department_votes.number_votes)
FROM employee_salary GROUP BY dept_id
Using RANK() function:
RANK provides the same numeric value for ties (for example 1, 1, 2, 4, 5).
SELECT *
FROM (
SELECT dept_id,
PersonName,
Salary,
RANK() OVER(PARTITION dept_id ORDER BY Salary DESC) AS SortBySalary
FROM employee_salary
)
WHERE SortBySalary = 1
Also, see this answer using MAX() function.
your table isn't clear to me. i can't understand why you're creating separate tables for all departments.
assuming you make two different tables, one for employees and one for department. this will make queries simpler for future and efficient database. In that case:
+----------+------------+------+-----+
|EmployeeID|EmployeeName|Salary|DepNo|
+----------+------------+------+-----+
| |
+----------+------------+------+-----+
+-----+-------+
|DepNo|DepName|
+-----+-------+
| |
+-----+-------+
SELECT DepName, EmployeeName, salary
FROM Department d
INNER JOIN Employee e on e.DepNo = d.DepNo
INNER JOIN
(
SELECT DepNo, MAX(salary) sal
FROM Employee
GROUP BY DepNo
) ss ON e.DepNo = ss.DepNo
AND e.salary = ss.sal;

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

how to express DENSE_RANK with ANSI SQL?

Is it possible to express the statment below by ANSI SQL? Since the example below belongs to PL/SQL. Thanks in advance.
SELECT department_id,
MIN(salary) KEEP (DENSE_RANK FIRST ORDER BY commission_pct) "Worst",
MAX(salary) KEEP (DENSE_RANK LAST ORDER BY commission_pct) "Best"
FROM employees
GROUP BY department_id;
DEPARTMENT_ID Worst Best
------------- ---------- ----------
10 4400 4400
20 6000 13000
30 2500 11000
40 6500 6500
50 2100 8200
60 4200 9000
70 10000 10000
80 6100 14000
90 17000 24000
100 6900 12000
110 8300 12000
7000 7000
This returns the same result (as far as I can tell) but does not need a join and is ANSI SQL:
select department_id,
min(case when min_comm = 1 then salary end) as worst,
max(case when max_comm = 1 then salary end) as best
from (
select department_id,
salary,
dense_rank() over (partition by department_id order by commission_pct desc) as max_comm,
dense_rank() over (partition by department_id order by commission_pct) as min_comm
from employees
) t
group by department_id
order by 1;
You can use self-joins instead of analytics in most cases. Here's an equivalent of your MAX(salary) KEEP (DENSE_RANK LAST ORDER BY commission_pct):
SELECT department_id, MAX(salary)
FROM employees e
WHERE (department_id, commission_pct) IN
(SELECT department_id,
MAX(commission_pct)
FROM employees
GROUP BY department_id)
GROUP BY department_id
Obviously getting both the MAX and MIN would be a bit trickier (and uglier) but is doable.
This construct avoids additional join to employees table. In ANSI SQL you would have to 1st query the highest commission_pct per department and then join the employees (again) to find salaries which have this highest commission_pct
In ANSI SQL it would like something like this:
select * from
(
SELECT department_id,
MIN(commission_pct) max_c
MAX(commission_pct) min_c
FROM employees
GROUP BY department_id
) e1
join employees e2
on (e1.department_id = e2.department_id and e1.max_c = e2.commission_pct)
join employees e3
on (e1.department_id = e3.department_id and e1.min_c = e3.commission_pct)
Even this is not 100% correct.
Having given this some more thought, I'll take a stab at it. I think you are trying to show the highest and lowest value (salary in the example) for each group(deptid) using ANSI SQL? Here's a super-simplistic example of it (using DENSE_RANK()) that should work on any ANSI compliant db:
SQL FIddle
select
t1.deptid,
t1.salary as Highest,
t2.salary as Lowest
from
(
select
deptid,
salary,
dense_rank() over (partition by deptid order by salary desc) as First --rank desc for highest
from
salaries
) T1
inner join
(
select
deptid,
salary,
dense_rank() over (partition by deptid order by salary asc) as worst -- rank ascending for lowest
from
salaries
)T2
on
t1.deptid = t2.deptid
where
t1.first = 1 --GET THE HIGHEST SALARY
and t2.worst = 1 -- GET THE LOWEST
Using min and max would also work and be a lot simpler:
Another SQL Fiddle
select
deptid,
max(salary) as Highest,
min(salary) as Lowest
from
salaries
group by
deptid