Group by clause to get name of highest paid employee - sql

I have a table Employee with fields dept, employee ans salary. I want a query to list Department wise highest salaries and name of the employee with that salary.
I know it is simple. I googled but found answers like this, which lists only the department and salary
SELECT dept, SUM (salary)
FROM employee
GROUP BY dept;

SELECT e1.*
FROM employee e1
JOIN (SELECT dept, MAX(salary) FROM employee GROUP BY dept) e2 ON
e1.dept = e2.dept AND e1.salary = e2.salary

SQL Server 2008 supports Window Functions which help you get what you want.
WITH recordList
AS
(
SELECT dept, employeeName, salary,
DENSE_RANK() OVER (PARTITION BY dept ORDER BY salary DESC) rn
FROM employee
)
SELECT dept, employeeName, salary
FROM recordList
WHERE rn = 1
SQLFiddle Demo
TSQL Ranking Function

SELECT e.*, d.deptname
FROM employee e
JOIN department d ON e.deptid = d.deptid
WHERE EXISTS (SELECT 1
FROM employee e_in
JOIN department d_in ON e_in.deptid = d_in.deptid
WHERE d_in.deptid = d.deptid
GROUP BY d_in.deptid
HAVING MAX(e_in.salary) = e.salary)

This will do it.
SELECT E1.DEPT, E2.ENAME, E1.HIGHEST_SALARY
FROM
(SELECT DEPT, MAX(SALARY) HIGHEST_SALARY
FROM EMPLOYEE
GROUP BY DEPT) E1
INNER JOIN EMPLOYEE E2 ON E1.HIGHEST_SALARY = E2.SALARY
AND E1.DEPT = E2.DEPT

select * from (select salary,last_name,dense_rank()
over (order by salary desc)
sal_rank from employees) where sal_rank <=3;
That's all... this is the output below:
SALARY LAST_NAME SAL_RANK
---------- ------------------------- ----------
24000 King 1
17000 Kochhar 2
17000 De Haan 2
14000 Russell 3

Related

How to retrieve highest salary for each department across employees?

I am trying to compile a query which gives me the highest salary per each department and for each unique employee. The complexity is that 1 employee can be part of multiple departments.
In case the same employee has the highest salary in several departments, only the department with a lower salary should show. This is my start but I am not sure how to continue from here:
select max(salary) as salary, dd.dept_name,d.emp_no
from salaries s
inner join dept_emp d on
s.emp_no=d.emp_no
inner join departments dd on
d.dept_no=dd.dept_no
group by 2,3;
My output is:
What should I modify from here?
For an employee, you seem to only want to include the department with the smallest salary. I would recommend using window functions:
select s.*
from (select s.*,
rank() over (partition by dept_name order by salary desc) as seqnum_d
from (select s.*, d.dept_name,
rank() over (partition by dept_name order by salary) as seqnum_ed
from salaries s join
dept_emp d
on s.emp_no = d.emp_no join
departments dd
d.dept_no = dd.dept_no
) s
where seqnum_ed = 1
) s
where seqnum_d = 1;
Something like this?
select m.salary, m.emp_no, salary.dept_name from salary,
(select emp_no, min(salary) salary from salary group by emp_no) m
where
m.emp_no=salary.emp_no and m.salary=salary.salary;

How to find dept name that has the highest average salary within two tables

Having two tables
Employee
Id
Name
Salary
DepartmentId
and
Departament
Id
Name
How can I get the highest average salary within two tables
like
Joe and Max belong to dept 1 so, avg is (70K+90K)/2
= 80K
and
Henry and Sam belog to dept 2, avg is (80K + 60K)/2=70k
so How to select the greatest avg salary by depto?, in this case
IT 80K
i have been trying:
'group the salary by each department and use the Max function to obtain the highest one.
select
Department.Name as Department,
T.M as Salary
from
Employee,
Department,
(select DepartmentId as ID, Max(Salary) as M from Employee group by DepartmentId) as T
where
Employee.Salary = T.M and
Department.Id = T.ID and
Employee.DepartmentId = Department.Id
enter image description here
If multiple department having same maximum avg salary then this solution will return multiple rows.
SELECT *
FROM(
SELECT d.Id, d.Name, AVG(e.Salary) avg_salary, RANK() OVER(ORDER BY AVG(e.Salary) DESC) AS rank_
FROM Employee e
INNER JOIN Departament d ON e.DepartmentId = d.Id
GROUP BY d.Id, d.Name
)T
WHERE rank_ = 1
If you want to get the average just for the department, you can use in this way.
select DepartmentId as ID, de.name as Deptname, Avg(Salary) as M from Employee em1
join Department de on de.departmentID = em1.DepartmentId
group by DepartmentId, de.name
If you want employee name along with highest average then you can use this approach as well.
select
Deptname as Department,
e.Name as Employeename,
z.M as Salary
from
Employee e
join
( select DepartmentId,Deptname, M, row_number() (order by m desc) rownum from ( select DepartmentId as ID, de.name as Deptname, Avg(Salary) as M from Employee em1
join Department de on de.departmentID = em1.DepartmentId
group by DepartmentId, de.name) as T) z
on
e.DepartmentId = T.DepartmentId and z.rownum = 1
If you want a full answer, you should provide DDL, sample data and desired result.
If I understand you correctly, you are looking for something like:
SELECT DepartmentID, AVG(Salary) AS AverageSalaryForDept
FROM Employee
GROUP BY DepartmentID
ORDER BY AverageSalaryForDept DESC;
This will give you all the averages, ordered from the highest to the lowest. Now if you want just the top one, add a FETCH clause:
SELECT DepartmentID, AVG(Salary) AS AverageSalaryForDept
FROM Employee
GROUP BY DepartmentID
ORDER BY AverageSalaryForDept DESC
OFFSET 0 ROWS FETCH NEXT 1 ROW ONLY;
HTH

Highest Salary in each department

I have a table EmpDetails:
DeptID EmpName Salary
Engg Sam 1000
Engg Smith 2000
HR Denis 1500
HR Danny 3000
IT David 2000
IT John 3000
I need to make a query that find the highest salary for each department.
SELECT DeptID, MAX(Salary) FROM EmpDetails GROUP BY DeptID
The above query is the accepted answer but it will not work for the following scenario. Let's say we have to find the employees with the highest salary in each department for the below table.
DeptID
EmpName
Salary
Engg
Sam
1000
Engg
Smith
2000
Engg
Tom
2000
HR
Denis
1500
HR
Danny
3000
IT
David
2000
IT
John
3000
Notice that Smith and Tom belong to the Engg department and both have the same salary, which is the highest in the Engg department. Hence the query "SELECT DeptID, MAX(Salary) FROM EmpDetails GROUP BY DeptID" will not work since MAX() returns a single value. The below query will work.
SELECT DeptID, EmpName, Salary FROM EmpDetails
WHERE (DeptID,Salary) IN (SELECT DeptID, MAX(Salary) FROM EmpDetails GROUP BY DeptID)
Output will be
DeptID
EmpName
Salary
Engg
Smith
2000
Engg
Tom
2000
HR
Danny
3000
IT
John
3000
Assuming SQL Server 2005+
WITH cteRowNum AS (
SELECT DeptID, EmpName, Salary,
DENSE_RANK() OVER(PARTITION BY DeptID ORDER BY Salary DESC) AS RowNum
FROM EmpDetails
)
SELECT DeptID, EmpName, Salary
FROM cteRowNum
WHERE RowNum = 1;
If you want to show other parameters too along with DeptId and Salary like EmpName, EmpId
SELECT
EmpID
, Name,
, Salary
, DeptId
FROM Employee
where
(DeptId,Salary)
in
(select DeptId, max(salary) from Employee group by DeptId)
SELECT empName,empDept,EmpSalary
FROM Employee
WHERE empSalary IN
(SELECT max(empSalary) AS salary
From Employee
GROUP BY EmpDept)
Select empname,empid,Sal,DeptName from
(Select e.empname,e.empid,Max(S.Salary) Sal,D.DeptName, ROW_NUMBER() Over(partition by D.DeptName order by s.salary desc) Rownum
from emp e inner join Sal S
on e.empid=s.empid
inner join Dept d on e.Deptid=d.Deptid
group by e.empname,e.empid,D.DeptName,s.Salary
) x where Rownum = 1
This will work if the department, salary and employee name are in the same table.
select ed.emp_name, ed.salary, ed.dept from
(select max(salary) maxSal, dept from emp_dept group by dept) maxsaldept
inner join emp_dept ed
on ed.dept = maxsaldept.dept and ed.salary = maxsaldept.maxSal
Is there any better solution than this?
ermn, something like:
select
d.DeptID,
max(e.Salary)
from
department d
inner join employees e on d.DeptID = e.DeptID
group by
d.DeptID
WITH cteRowNum AS (
SELECT DeptID, EmpName, Salary,
ROW_NUMBER() OVER(PARTITION BY DeptID ORDER BY Salary DESC) AS RowNum
FROM EmpDetails
)
SELECT DeptID, EmpName, Salary,Rownum
FROM cteRowNum
WHERE RowNum in(1,2);
SELECT Employee_ID
, First_name
, last_name
, department_id
, Salary
FROM (SELECT Employee_ID
, First_name
, last_name
, department_id
, Salary
, MAX(salary) OVER (PARTITION BY department_id) dept_max_sal
FROM EMPLOYEES) AS Emp
WHERE salary = dept_max_sal;
Use following command;
SELECT A.*
FROM #EmpDetails A
INNER JOIN ( SELECT DeptID ,
MAX(salary) AS salary
FROM #EmpDetails
GROUP BY DeptID
) B ON A.DeptID = B.DeptID
AND A.salary = B.salary
ORDER BY A.DeptID
SELECT DeptID, MAX(Salary)
FROM EmpDetails
GROUP BY DeptID
This query will work fine, but the moment if you want to fetch some others details related to the employee having the highest salary will contradict.
You can use :
SELECT DepatID, a , b, c
FROM EmpDetails
WHERE Salary IN (
SELECT max(Salary)
FROM EmpDetails
GROUP BY DeptID
);
if you will use the previous query it will only reflects the records of the min val except the salary as you have used the max function.
SELECT
DeptID,
Salary
FROM
EmpDetails
GROUP BY
DeptID
ORDER BY
Salary desc
***
> /*highest salary by each dept*/
***
select d.Dept_Name,max(e.salary)
from emp_details as e join Dept_Details as d
on e.d_id=d.Dept_Id
group by d.Dept_Name
select distinct e.d_id,d.Dept_Name
from emp_details as e join Dept_Details as d
on e.d_id=d.Dept_Id
select e.salary,d.Dept_Name,d.Dept_Id
from emp_details as e join Dept_Details as d
on e.d_id=d.Dept_Id
/////simplest query for max salary dept_wise////
Use the below quesry:
select employee_name,salary,department_id from emp where salary in(select max(salary) from emp group by department_id);
select empno
from EMP e
where salary=(select max(sal)
from EMP w
where groupby w.deptno having e.deptno=w.deptno)
I hope it will work...
Use correlated subquery:
SELECT DeptID, EmpName, Salary
FROM EmpDetails a
WHERE Salary = (SELECT MAX(Salary)
FROM EmpDetails b
WHERE a.DeptID = b.DeptID)
This is the best possible solution for ORACLE:
Select * from (select customerid, city, freight,
row_number() over (partition by customerid order by freight desc) Row_Number from
(select orders.orderId, customers.CUSTOMERID, customers.city, orders.FREIGHT from orders inner join customers on orders.customerid = customers.customerid where customers.country='Germany' order by customers.customerid, orders.freight desc)
order by customerid, freight desc) where Row_Number<=2;
Notice here I have used partition by clause for marking row number, this is majorly because we need to partition the records grouping them according to customer id. I have used two inner queries here. The inner most query is to give a view which is sorted according to customer ID and decreasing order of cost. Now from that we need to obtain always top two records so firstly we need to name them and then we need to filter them according to rownum. Second level query is to mark rownum according to customer ID. And final query will filter the result according to rownum. For every partition.
select deptid, empname, salary from
(Select deptid, empname,salary,
rank() Over(Partition by deptid order by salary desc)as rank from
EmpDetails) emp
where emp.rank = 1
First ranks each employee by salary in descending order having highest
rank 1 and then selects only deptid, empname, salary. You can do this for
all Nth member of the group.
SELECT empname
FROM empdetails
WHERE salary IN(SELECT deptid max(salary) AS salary
FROM empdetails
group by deptid)
select a.*
from EmpDetails a
inner join
(
select DeptID,max(Salary) as Salary
from EmpDetails group by DeptID
)b
on a.DeptID = b.DeptID and a.Salary = b.Salary
Here is a way to get maximum values and names on any version of SQL.
Test Data:
CREATE TABLE EmpDetails(DeptID VARCHAR(10), EmpName VARCHAR(10), Salary DECIMAL(8,2))
INSERT INTO EmpDetails VALUES('Engg','Sam',1000)
INSERT INTO EmpDetails VALUES('Engg','Smith',2000)
INSERT INTO EmpDetails VALUES('HR','Denis',1500)
INSERT INTO EmpDetails VALUES('HR','Danny',3000)
INSERT INTO EmpDetails VALUES('IT','David',2000)
INSERT INTO EmpDetails VALUES('IT','John',3000)
Example:
SELECT ed.DeptID
,ed.EmpName
,ed.Salary
FROM (SELECT DeptID, MAX(Salary) MaxSal
FROM EmpDetails
GROUP BY DeptID)AS empmaxsal
INNER JOIN EmpDetails ed
ON empmaxsal.DeptID = ed.DeptID
AND empmaxsal.MaxSal = ed.Salary
Not the most elegant, but it works.
SELECT D.DeptID, E.EmpName, E.Salary
FROM Employee E
INNER JOIN Department D ON D.DeptId = E.DeptId
WHERE E.Salary IN (SELECT MAX(Salary) FROM Employee);
select * from (
select a.* from EmpDetails a
right join (select DeptID,max(salary) as Salary from EmpDetails group by DeptID) b
on b.DeptID=a.DeptID and b.salary=a.salary ) as c group by c.DeptID;
The below query will display employee name with their respective department name in which that particular employee name is having highest salary.
with T as
(select empname, employee.deptno, salary
from employee
where salary in (select max(salary)
from employee
group by deptno))
select empname, deptname, salary
from T, department
where T.deptno=department.deptno;
I executed the above query successfully on Oracle database.
If you just want to get the highest salary from that table, by department:
SELECT MAX(Salary) FROM TableName GROUP BY DeptID
IF you want Department and highest salary, use
SELECT DeptID, MAX(Salary) FROM EmpDetails GROUP BY DeptID
if you want more columns in employee and department, use
select Department.Name , emp.Name, emp.Salary from Employee emp
inner join (select DeptID, max(salary) [salary] from employee group by DeptID) b
on emp.DeptID = b.DeptID and b.salary = emp.Salary
inner join Department on emp.DeptID = Department.id
order by Department.Name
if use salary in (select max(salary...)) like this, one person have same salary in another department then it will fail.
The below listed query will list highest salary in each department.
select deptname, max(salary) from department, employee where
department.deptno=employee.deptno group by deptname;
I executed this query successfully on Oracle database.
with ctesal as (
select DepartmentId , Name , Salary, ROW_Number() OVER (partition by DepartmentId
order by Salary desc) as RowNum
from dbo.Employee
)
select DepartmentId , Name , Salary , RowNum from ctesal where RowNum =2;
This is applicable to SQL server.
ROW_Number is a inbuilt function in SQL server .It gives count starting from 1 based on partition by and order by clause. At the end, We can write where condition based on our requirements.
I have like 2 approaches using one with Rank and the other with ROW_NUMBER
This is my sample data
Age Name Gender Salary
----------- -------------------------------------------------- ---------- -----------
1 Mark Male 5000
2 John Male 4500
3 Pavan Male 5000
4 Pam Female 5500
5 Sara Female 4000
6 Aradhya Female 3500
7 Tom Male 5500
8 Mary Female 5000
9 Ben Male 6500
10 Jodi Female 7000
11 Tom Male 5500
12 Ron Male 5000
13 Ramani Female 7000
So here is my first query to find max salary and the person with that max salary for each Gender
with CTE as(
select RANK() over(partition by Gender Order by Salary desc) as [Rank],* from employees)
select * from CTE where [Rank]=1
Rank Age Name Gender Salary
-------------------- ----------- -------------------------------------------------- ---------- -----------
1 10 Jodi Female 7000
1 13 Ramani Female 7000
1 9 Ben Male 6500
So in this case, we can see there is a tie between these 2 female employees "Jodi" and "Ramani". In that case, As a tie-breaker I want to make use of Age as a deciding factor and person with more age is supposed to be displayed
with CTE as(
select RANK() over(partition by Gender Order by Salary desc,age desc) as [Rank],* from employees)
select * from CTE where [Rank]=1
Rank Age Name Gender Salary
-------------------- ----------- -------------------------------------------------- ---------- -----------
1 13 Ramani Female 7000
1 9 Ben Male 6500
Usually, in this case for finding the highest salary, it doesn't make much difference even if
Rank, Dense_Rank, or Row_Number() are used. But they have some impact in other cases.
Thank you #JoeStefanelli for his answer (https://stackoverflow.com/a/8477083/4691279). He provided SQL Server 2005+ version and I used the same to create the Oracle version:
WITH cteRowNum(dep_id, emp_id, Salary, RowNums) AS (
SELECT dep_id, emp_id, Salary,
DENSE_RANK() OVER(PARTITION BY dep_id ORDER BY Salary DESC) AS RowNums
FROM employee
)
SELECT cteRowNum.dep_id, cteRowNum.emp_id, cteRowNum.Salary
FROM cteRowNum
WHERE cteRowNum.RowNums = 1;
You can test this using livesql.oracle.com, below are my DDLs and DMLs you can use:
create table employee (
emp_id varchar2(50) NOT NULL,
dep_id varchar2(50) NOT NULL,
salary number not null
);
create table department (
dep_id varchar2(50) NOT NULL,
dep_name varchar2(50) NOT NULL
);
insert into employee values (100, 5000, 1000000);
insert into employee values (200, 5000, 2000000);
insert into employee values (300, 5000, 3000000);
insert into employee values (400, 6000, 1500000);
insert into employee values (500, 6000, 1500000);
insert into employee values (600, 7000, 1000000);
insert into employee values (700, 7000, 1000000);
insert into employee values (800, 7000, 2000000);
insert into department values (5000, 'dep 1');
insert into department values (6000, 'dep 2');
insert into department values (7000, 'dep 3');
And below is the success screenshot of the query:

SQL query: how can I get "id" of department in which employees receive the maximum salary?

How can I get id of department in which employees receive the maximum salary:
Employee table: Empl (ID, FirstName, LastName, Salary, DeptId)
Departments table: Dept (ID, City)
rus (Вывести “id” подразделения, в котором сотрудники получают максимальную заработную плату.)
EDIT: Changed SUM(Salary) to AVG(Salary) based on comments on the question.
SELECT TOP 1 DeptId
FROM Employees
GROUP BY DeptId
ORDER BY AVG(Salary) DESC
SELECT TOP 1 B.*
FROM (SELECT DeptId, AVG(Salary) AvgSalary
FROM Empl
GROUP BY DeptId) A
INNER JOIN Dept B
ON A.DeptId = B.Id
ORDER BY AvgSalary DESC
To get the one single Department's ID where the highest single salary is paid:
SELECT TOP 1 DeptID
FROM dbo.Empl
ORDER BY Salary DESC
Or are you looking for something else?
I would assume you mean max average salary of a department and not the single highest salary across all departments.
However it seems all you would have to do is use the following SQL functions
MAX function
AVG function
group by department ID and viola.
Thought I agree with the comments above, I will assume you are doing this for research ;-)
select id
from dept
where id = ( select deptid
from ( select max(avg_salary), deptid
from ( select deptid, avg(salary) as avg_salary
from empl
group by deptid )
group by deptid )
)
:-)
SELECT DepartmentId
FROM Employee
WHERE Salary = (SELECT MAX(Salary) FROM Employee)

Query simplification by using oracle sample database

Task :
List Name and salary of highest and lowest paid employee from each department.
You can perform the queries for highest and lowest separately also.
Tried Query :
SELECT dept.deptno,
dname,
minsal,
maxsal
FROM dept,
(SELECT deptno,
Max (sal) MAXSAL
FROM emp
GROUP BY deptno) MAXSALARY,
(SELECT deptno,
Min (sal)MINSAL
FROM emp
GROUP BY deptno) MINSALARY
WHERE MAXSALARY.deptno = dept.deptno
AND MINSALARY.deptno = dept.deptno;
Result
The Result is correct.
Question)
Is there any other way to simplify the query?
You can use ORACLE's window functions like row_number combined with conditional aggregation using CASE EXPRESSION :
SELECT t.ename,t.dname,
MAX(CASE WHEN t.low_ind = 1 then t.salary END),
MAX(CASE WHEN t.high_ind = 1 then t.salary END)
FROM (SELECT e.name as ename,d.name as dname,e.salary,
ROW_NUMBER() OVER(PARTITION BY d.name ORDER BY e.salary ASC) as low_ind,
ROW_NUMBER() OVER(PARTITION BY d.name ORDER BY e.salary DESC) as high_ind
FROM emp e
INNER JOIN dept d
ON(d.deptno = e.deptno)) t
GROUP BY t.ename,t.dname
EDIT: if all you need is the min and max salary on each department then thats a simple group by clause :
SELECT d.deptno,d.dname,MIN(e.salary) as min_sal,MAX(e.salary) as max_sal
FROM dept d
INNER JOIN emp e
ON(d.deptno = e.deptno)
GROUP BY d.deptno,d.name
SELECT d.dname, Max(e.sal) MAXSAL, Min(e.sal) MINSAL
FROM dept d, emp e
WHERE d.deptno = e.deptno
group by d.dname