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;
Related
I want to display the lowest earning employees of each department based on salary using min().
I have tables of employees with id, first name, last name, department id, salary
and departments, department_id, name department id from 1 to 5.
I am having trouble doing this, I only know how to start
SELECT name, surname from employees WHERE...
You would use min() for this. You would use window functions:
select e.*
from (select e.*,
rank() over (partition by department_id order by salary) as seqnum
from employees e
) e
where seqnum = 1
order by department_id;
With rank()over() ranking window function you can have your rows within a group ranked as you wish. Here we have ranked all the employees starting with lowest salary in a department. Now if we select rows with rn =1 then it will select employees from a department with lowest salary.
Then joined the result with department table to get the name of the
With lowestEarningEmployees as
(
id, first_name, last_name, department_id, salary, rank()over(partition by department_id order by salary)rn from employees
)
select le.id, le.first_name, le.last_name, le.department_id,d.name, le.salary,
from lowestEarningEmployees le inner join departments d on le.department_id=d.department_id
** If more than one employee in a department have lowest salary all of them will be selected. If you want to select only one employee with lowest salary then you need to use row_number() instead of rank().
You can also use subquery to have your desired result (Though I would suggest to use first one) :
Select e.id, e.first_name, e.last_name, e.department_id, d.name, e.salary
from employees e inner join department d on e.department_id = d.department_id
where e.salary=(select min(salary) from employees empl where e.department_id=empl.department_id)
In the employees table I have id_departament
And I can`t figure it out how to extract the avg salary for every employee
Use window functions if your RDBMS supports them:
select *
from (
select e.*, avg(salary) over(partition by id_department) avg_salary_dept
from employee e
) t
where salary > avg_salary_dept
Alternatively, you can join the table with an aggregate query that computes the average salary per department:
select e.*
from employee e
inner join (
select id_department, avg(salary) avg_salary_dept
from employee
group by id_department
) a on e.id_department = a.id_department and e.salary > a.avg_salary_dept
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
I have a table with Employees, Departments and Salaries and I would like to get min and max salaries per department (what is just min/max with group by on department), but how to count how many Employees earn that min and max salary per department?
Select Department,
Count(distinct EmployeeID) as Employees,
Min(Salary) as Min,
Max(Salary) as Max
From Employees
Group by Department;
You need to make your query as a subquery for the following one :
Select Department, count(*) as "Count People"
From Employees
Where (Department,Salary) IN
(
Select Department, Min(Salary)
From Employees
Group by Department
Union all
Select Department, Max(Salary)
From Employees
Group by Department
)
Group by Department;
Rextester Demo
Maybe you need 2 distinct values for the counters of minimum and maximum salaries of each department:
SELECT t1.Department, t1.MinCounter, t2.MaxCounter FROM
(SELECT t.Department, COUNT(*) AS MinCounter
FROM
(SELECT Department, MIN(Salary) AS MinSalary FROM Employees
GROUP BY Department) AS t
INNER JOIN Employees
ON (t.MinSalary = Employees.Salary) AND (t.Department = Employees.Department)
GROUP BY t.Department) AS t1
INNER JOIN
(SELECT t.Department, COUNT(*) AS MaxCounter
FROM
(SELECT Department, MAX(Salary) AS MaxSalary FROM Employees
GROUP BY Department) AS t
INNER JOIN Employees
ON (t.MaxSalary = Employees.Salary) AND (t.Department = Employees.Department)
GROUP BY t.Department) AS t2
ON t1.Department = t2.Department
The above query consists of 2 subqueries joined by Department, each of which fetches the counter of the minimum and the maximum salary per department. If you also want included in the query the amounts of the minimum and the maximum salary per department, then check this:
SELECT t1.Department, t1.MinSalary, t1.MinCounter, t2.MaxSalary, t2.MaxCounter
FROM
(SELECT t.Department, t.MinSalary, COUNT(*) AS MinCounter
FROM (SELECT Department, MIN(Salary) AS MinSalary FROM Employees
GROUP BY Department) AS t
INNER JOIN Employees
ON (t.Department = Employees.Department)
AND (t.MinSalary = Employees.Salary)
GROUP BY t.Department, MinSalary) AS t1
INNER JOIN
(SELECT t.Department, t.MaxSalary, COUNT(*) AS MaxCounter
FROM (SELECT Department, MAX(Salary) AS MaxSalary FROM Employees
GROUP BY Department) AS t
INNER JOIN Employees
ON (t.Department = Employees.Department)
AND (t.MaxSalary = Employees.Salary)
GROUP BY t.Department, MaxSalary) AS t2
ON t1.Department = t2.Department
You can get the min and max salaries in a subquery, then count how many employees have those salaries in an outer query, like so: https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=b89ac6b76112bf7db65ce6e37754198b
select agg.*
, count(case when e.Salary = agg.MinSalary then 1 end) EmployeesWithMin
, count(case when e.Salary = agg.MaxSalary then 1 end) EmployeesWithMax
from
(
select Department
, count(1) EmployeesInDepartment
, min(Salary) MinSalary
, max(Salary) MaxSalary
from Employees
group by Department
) agg
inner join Employees e
on e.Department = agg.department
and e.Salary in (agg.MaxSalary, agg.MinSalary)
group by agg.Department
, agg.EmployeesInDepartment
, agg.MinSalary
, agg.MaxSalary
Or an alternative approach: https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=8a5e539fcd3e5985d44f86b1e331f030
select agg.Department
, min(agg.MinSalary) MinSalary
, max(agg.MaxSalary) MaxSalary
, count(case when Salary = MinSalary then 1 end) EmployeesWithMin
, count(case when Salary = MaxSalary then 1 end) EmployeesWithMax
from
(
select Department
, min(Salary) over (partition by Department) MinSalary
, max(Salary) over (partition by Department) MaxSalary
, Salary
from Employees
) agg
group by agg.Department
The former may be simpler to understand for a beginner. The latter is less verbose, so easier to read. i.e. Pick whichever you're more comfortable supporting / whichever makes most sense to you.
In terms of performance, the second performed slightly better for my sample data; but a number of variables may influence this (number of rows, spread of values, availability of indexes), so it's best to test on data as similar to real-world as possible if you need to pick the optimal query.
Let me know if any of the methods used here aren't familiar to you and I can add explanations as required.
O community, do you know how I could select the department_ID, and lowest salary of the department with the highest average salary? Or how to eliminate the'ORA-00934: group function not allowed here' issue? Would I need to use two subqueries?
So far, this is what I've come up with, trying to get the department_ID of the highest paid department:
SELECT department_ID, MIN(salary
FROM employees
WHERE department_ID = (SELECT department_ID
FROM employees WHERE salary = MAX(salary));
Thank you, your assistance is greatly appreciated.
I can't test this, but it should work:
;WITH DepartmentsSalary AS
(
SELECT department_ID, AVG(Salary) AvgSalary, MIN(Salary) MinSalary
FROM employees
GROUP BY department_ID
)
SELECT department_ID, MinSalary
FROM ( SELECT department_ID, AvgSalary, MAX(AvgSalary) OVER() MaxSalary, MinSalary
FROM DepartmentsSalary) D
WHERE MaxSalary = AvgSalary
You can use join (then you have just one sub query)
select e1.department_ID, min(e1.salary)
from employees e1
join (
select avg_query.department_ID, max(avg_query.avg_value)
from (
select department_ID, avg(salary) as avg_value
from employees
group by department_ID
) avg_query
) e2 on e2.department_ID = e1.department_ID
;
First sub-query returned average salary for all departments
Next sub-query based on first sub-query returned highest average
salary and related department_ID
Main query returned min salary for department_ID with highest average
salary