Highest paid employee + average salary of the departments - sql

An employee belongs to a department (foreign key = D_ID). An employee has a SSN (primary key), name, salary and D_ID.
A department has multiple employees (primary key = ID)
I want a query that returns Department name| Name of Highest Paid Employee of that department | His Salary | Average salary of employees working in the same department.
I know how to select the first part:
SELECT
D.name, E.name, E.salary
FROM
Employee E, Department D
WHERE
salary IN (SELECT MAX(E.salary)
FROM Employee E
GROUP BY E.D_ID)
AND E.D_ID = D.ID
I know also how to select the last part:
SELECT AVG(E.salary)
FROM Employee E
GROUP BY E.D_ID
How do I put these together in a single query?

You can use window functions for that:
select department_name, employee_name, salary, avg_dept_salary
from (
select e.name as employee_name,
d.name as department_name,
e.salary,
max(e.salary) over (partition by d.id) as max_dept_salary,
avg(e.salary) over (partition by d.id) as avg_dept_salary
from Employee E
join Department D on e.d_id = d.id
) t
where salary = max_dept_salary
order by department_name;
The above is standard ANSI SQL and runs on all modern DBMS.

I would do something like this:
SELECT d.name
, e.name
, e.salary
, n.avg_salary
FROM Department d
JOIN ( SELECT m.d_id
, MAX(m.salary) AS max_salary
, AVG(m.salary) AS avg_salary
FROM Employee m
GROUP BY m.d_id
) n
ON n.d_id = d.id
JOIN Employee E
ON e.d_id = d.id
AND e.salary = n.max_salary

Related

Why this select selects no rows

I am trying to select a highest earner in 'IT' department, but I keep selecting no rows.
Salary and names are in table called employees while department_name is in a table named departments.
Can anyone please explain why does this select no rows and how should I do it?
SELECT first_name, last_name, salary, department_name
FROM employees
JOIN departments on departments.department_id = employees.department_id
WHERE salary = (SELECT max(salary) FROM employees WHERE department_name = 'IT');
Why this select selects no rows?
Your query fails because there is no column department_name in the employees table. So your subquery does not do what you expect:
where salary = (SELECT max(salary) FROM employees WHERE department_name = 'IT');
If you want to do this with a subquery, you need to correlate it:
select e.first_name, e.last_name, e.salary, d.department_name
from employees e
inner join departments d on d.department_id = e.department_id
where
d.department_name = 'IT'
and e.salary = (select max(e1.salary)
from employees e1
where e1.department_id = e.department_id);
You can use dense_rank if there are more than one highest earner for IT department.
select
first_name,
last_name,
salary,
department_name
from
(
select
first_name,
last_name,
salary,
department_name,
dense_rank() over (partition by department_name order by salary desc) as rnk
FROM employees e
JOIN departments d
on d.department_id = e.department_id
where department_name = 'IT'
) val
where rnk = 1
Use row_number() :
SELECT t.*
FROM (SELECT emp.first_name, emp.last_name, dempt.salary, dempt.department_name,
ROW_NUMBER() OVER(PARTITION BY dept.department_name ORDER BY dept.salary DESC) AS SEQ
FROM employees emp JOIN
departments dept
ON dept.department_id = emp.department_id
WHERE dempt.department_name = 'IT'
) t
WHERE seq = 1;
If salary has ties then you can use rank() instead.

Join two table with department wise maximum salary

Department wise maximum salary in a table it's working:
select * from employee where (emp_dept, emp_sal)
in (select emp_dept, max(emp_sal) from employee group by emp_dept);
but my concern is : i want emp_id, emp_name, emp_sal, emp_dept column with department wise maximnum salary
customer table : cust_id, cust_name, emp_id
employee table : emp_id, emp_name, emp_sal, emp_dep
I think you want :
select e.emp_id, e.emp_name, e.emp_sal, e.emp_dept
from employee e
where e.emp_sal = (select max(e1.emp_sal) from employee e1 where e1.emp_dept = e.emp_dept);
Assuming you want all the records from the employee table with the maximum salary added, then you could use something like:
Select e.emp_id, e.emp_name, e.emp_sal, e.emp_dept, d.max_salary
from employee e
left join
(select emp_dept,max(emp_sal) as max_salary
from employee
group by emp_dept) d
ON e.emp_dept=d.emp_dept
The sub query calculates the maximum salary for each department and then using the left join you can get it into the final table.
If you want the employee details of the employee with the maximum salary, then:
Select e.emp_id, e.emp_name, e.emp_sal, e.emp_dept, d.max_salary
from employee e
inner join
(select emp_dept,max(emp_sal) as max_salary
from employee
group by emp_dept) d
ON e.emp_dept=d.emp_dept and e.emp_sal=d.max_salary
In this case the join is based on the salary component as well, thereby returning only the employees with the maximum salary. Hope this helps.
Just use a window function:
select e.*,
max(emp_sal) over (partition by emp_dept) as dept_max_sal
from employee ;

Simple SQL query not working out

click here for database model
Asked: Show for every department with at least 3 employees, the department's name and the amount of employees in that department born before 1967.
My code so far:
`Select department, department_name, numberofemployeesbefore1967 = ( select count(empleyee_id) from employee where year(dateofbirth) < 1967)
From employee inner join department on (department = department_id)
group by department, department_name
having count(*) >=3`
The output I have now: output
I feel like this is a really easy one, but I cannot find how to show only the employees born before 1967 for that specific department.
Anyone to help me out?
I check the year in the main query and >=3 in a subquery
SELECT department department_name, count(*)
FROM department d
JOIN employee e on d.department_id = e.department
WHERE YEAR(dateOfBirth) < 1967
AND (SELECT COUNT(*) FROM employee WHERE department = d.department_id) >= 3
GROUP BY d.id, d.name
Tweaked the subquery like so...
Select department, department_name, (select count(empleyee_id) from employee where year(dateofbirth) < 1967) AS numberofemployeesbefore1967
From employee inner join department on (department = department_id)
group by department, department_name
having count(*) >=3

Employees with largest salary in department

I found a couple of SQL tasks on Hacker News today, however I am stuck on solving the second task in Postgres, which I'll describe here:
You have the following, simple table structure:
List the employees who have the biggest salary in their respective departments.
I set up an SQL Fiddle here for you to play with. It should return Terry Robinson, Laura White. Along with their names it should have their salary and department name.
Furthermore, I'd be curious to know of a query which would return Terry Robinsons (maximum salary from the Sales department) and Laura White (maximum salary in the Marketing department) and an empty row for the IT department, with null as the employee; explicitly stating that there are no employees (thus nobody with the highest salary) in that department.
Return one employee with the highest salary per dept.
Use DISTINCT ON for a much simpler and faster query that does all you are asking for:
SELECT DISTINCT ON (d.id)
d.id AS department_id, d.name AS department
,e.id AS employee_id, e.name AS employee, e.salary
FROM departments d
LEFT JOIN employees e ON e.department_id = d.id
ORDER BY d.id, e.salary DESC;
->SQLfiddle (for Postgres).
Also note the LEFT [OUTER] JOIN that keeps departments with no employees in the result.
This picks only one employee per department. If there are multiple sharing the highest salary, you can add more ORDER BY items to pick one in particular. Else, an arbitrary one is picked from peers.
If there are no employees, the department is still listed, with NULL values for employee columns.
You can simply add any columns you need in the SELECT list.
Find a detailed explanation, links and a benchmark for the technique in this related answer:
Select first row in each GROUP BY group?
Aside: It is an anti-pattern to use non-descriptive column names like name or id. Should be employee_id, employee etc.
Return all employees with the highest salary per dept.
Use the window function rank() (like #Scotch already posted, just simpler and faster):
SELECT d.name AS department, e.employee, e.salary
FROM departments d
LEFT JOIN (
SELECT name AS employee, salary, department_id
,rank() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rnk
FROM employees e
) e ON e.department_id = d.department_id AND e.rnk = 1;
Same result as with the above query with your example (which has no ties), just a bit slower.
This is with reference to your fiddle:
SELECT * -- or whatever is your columns list.
FROM employees e JOIN departments d ON e.Department_ID = d.id
WHERE (e.Department_ID, e.Salary) IN (SELECT Department_ID, MAX(Salary)
FROM employees
GROUP BY Department_ID)
EDIT :
As mentioned in a comment below, if you want to see the IT department also, with all NULL for the employee records, you can use the RIGHT JOIN and put the filter condition in the joining clause itself as follows:
SELECT e.name, e.salary, d.name -- or whatever is your columns list.
FROM employees e RIGHT JOIN departments d ON e.Department_ID = d.id
AND (e.Department_ID, e.Salary) IN (SELECT Department_ID, MAX(Salary)
FROM employees
GROUP BY Department_ID)
This is basically what you want. Rank() Over
SELECT ename ,
departments.name
FROM ( SELECT ename ,
dname
FROM ( SELECT employees.name as ename ,
departments.name as dname ,
rank() over (
PARTITION BY employees.department_id
ORDER BY employees.salary DESC
)
FROM Employees
JOIN Departments on employees.department_id = departments.id
) t
WHERE rank = 1
) s
RIGHT JOIN departments on s.dname = departments.name
Good old classic sql:
select e1.name, e1.salary, e1.department_id
from employees e1
where e1.salary=
(select maxsalary=max(e.salary) --, e. department_id
from employees e
where e.department_id = e1.department_id
group by e.department_id
)
Table1 is emp - empno, ename, sal, deptno
Table2 is dept - deptno, dname.
Query could be (includes ties & runs on 11.2g):
select e1.empno, e1.ename, e1.sal, e1.deptno as department
from emp e1
where e1.sal in
(SELECT max(sal) from emp e, dept d where e.deptno = d.deptno group by d.dname)
order by e1.deptno asc;
SELECT
e.first_name, d.department_name, e.salary
FROM
employees e
JOIN
departments d
ON
(e.department_id = d.department_id)
WHERE
e.first_name
IN
(SELECT TOP 2
first_name
FROM
employees
WHERE
department_id = d.department_id);
`select d.Name, e.Name, e.Salary from Employees e, Departments d,
(select DepartmentId as DeptId, max(Salary) as Salary
from Employees e
group by DepartmentId) m
where m.Salary = e.Salary
and m.DeptId = e.DepartmentId
and e.DepartmentId = d.DepartmentId`
The max salary of each department is computed in inner query using GROUP BY. And then select employees who satisfy those constraints.
Assuming Postgres
Return highest salary with employee details, assuming table name emp having employees department with dept_id
select e1.* from emp e1 inner join (select max(sal) avg_sal,dept_id from emp group by dept_id) as e2 on e1.dept_id=e2.dept_id and e1.sal=e2.avg_sal
Returns one or more people for each department with the highest salary:
SELECT result.Name Department, Employee2.Name Employee, result.salary Salary
FROM ( SELECT dept.name, dept.department_id, max(Employee1.salary) salary
FROM Departments dept
JOIN Employees Employee1 ON Employee1.department_id = dept.department_id
GROUP BY dept.name, dept.department_id ) result
JOIN Employees Employee2 ON Employee2.department_id = result.department_id
WHERE Employee2.salary = result.salary
SQL query:
select d.name,e.name,e.salary
from employees e, depts d
where e.dept_id = d.id
and (d.id,e.salary) in
(select dept_id,max(salary) from employees group by dept_id);
Take look at this solution
SELECT
MAX(E.SALARY),
E.NAME,
D.NAME as Department
FROM employees E
INNER JOIN DEPARTMENTS D ON D.ID = E.DEPARTMENT_ID
GROUP BY D.NAME

Select the biggest value

I am trying to solve a simple problem but i am getting stack on the details.
I have 2 tables, one has employees and the other one has departments. My problem: I am trying to check which department has the most employees and output only that specific department.
So far I have:
select count(*) Number_of_employees
from department d, employee e
where d.department_id = e.department_id
group by department_name
which outputs:
NUMBER_OF_EMPLOYEES
----------------------
2
4
3
3
3
My goal is to to output only the department with the most employees which is the department with 4 employees.
I tried using the MAX and JOIN but i am not so good with join yet so any suggestions will be appreciated.
#Zsolt Botykai
I think this is correct, apart from order by needs to be DESC, and I don't think you can refer to number_of_employees inside the query. ( you can't in oracle anyway ).
select department_name
from
(select department_name
,number_of_employees
from
( select department_name, count(*) Number_of_employees
from department d, employee e
where d.department_id = e.department_id
group by department_name)
order by Number_of_employees DESC)
where rownum = 1
You could do it this way to avoid the rownum:
select
max(d.department_name) keep (dense_rank first order by count(1) desc) as department_name
, count(1) as number_of_employees
from employee e
inner join department d on (e.department_id = d.department_id)
group by d.department_name
;
select department_name from
( select department_name, count(*) Number_of_employees
from department d, employee e
where d.department_id = e.department_id
group by department_name
order by 2 desc )
where rownum = 1
should do.
HTH