Two aggregation functions group by - sql

I'm trying to print the department names that have the sum of all salaries bigger than the average sum on departments.
SELECT d.department_name, SUM(e.salary)
FROM departments d, employees e
WHERE d.department_id = e.department_id
GROUP BY d.department_name
HAVING SUM(e.salary) > (SELECT AVG(SUM(salary)) from employees);
In the second select, after what do I have to group by AVG(SUM(salary))?

You need to repeat the first query in the condition. This can be done with the WITH clause.
WITH dept_sums AS (SELECT d.department_name, SUM(e.salary) sum_salary
FROM departments d, employees e
WHERE d.department_id = e.department_id
GROUP BY d.department_name)
SELECT * FROM dept_sums d_s_1 WHERE d_s_1.sum_salary > (SELECT AVG(sum_salary) FROM dept_sums d_s_2);

This is where window (analytic) functions come in handy. Below I am using AVG() as an analytic function to calculate the average total salary across all departments.
SELECT department_name, dept_salary FROM (
SELECT d.department_name, SUM(e.salary) AS dept_salary
, AVG(SUM(e.salary)) OVER ( ) AS avg_dept_salary
FROM departments d INNER JOIN employees e
ON d.department_id = e.department_id
GROUP BY d.department_name
) WHERE dept_salary > avg_dept_salary;

Related

Oracle: range of standard deviation of salary in correlated subquery

I am using an Oracle Developer Database and I have the two tables, Employees and Departments :
I am supposed to find (using a correlated subquery) for each department all the employees, which have a salary within the range of the salary-standard deviation of every single department.
This is what I have tried so far:
SELECT d.department_name, e.employee_id, e.last_name, AVG(e.salary), e.salary
FROM hr.employees e
JOIN hr.departments d
on e.department_id = d.department_id
WHERE e.salary IN
(SELECT salary
FROM hr.employees
WHERE salary >
(SELECT ROUND(AVG(e.salary)-STDDEV(e.salary),2)
FROM hr.employees) AND salary < (SELECT ROUND(AVG(e.salary) + STDDEV(e.salary),2) FROM hr.employees)
GROUP BY d.department_name,
e.employee_id, e.last_name, e.salary;
Even though this query has the correct syntax, it does not show any result.
This other (partial) approach works but how can I query at the same time the employee table?
SELECT d.department_name, e.department_id, ROUND(AVG(e.salary) + STDDEV(e.salary), 2)
AS standard_deviation_max,
ROUND(AVG(e.salary) - STDDEV(e.salary), 2)
AS standard_deviation_min
FROM hr.employees e
JOIN hr.departments d
on e.department_id = d.department_id
GROUP BY department_name, e.department_id;
Since I am new to SQL, I would really appreciate any hint. Thank you in advance
You can use your query to find the employee details and then correlate the salary to the average ± the standard deviation:
SELECT d.department_name,
e.employee_id,
e.last_name,
e.salary
FROM hr.employees e
JOIN hr.departments d
on e.department_id = d.department_id
WHERE EXISTS (
SELECT 1
FROM hr.employees x
HAVING e.salary BETWEEN AVG(e.salary) + STDDEV(e.salary)
AND AVG(e.salary) + STDDEV(e.salary)
);
or, you can use analytic functions:
SELECT department_name,
employee_id,
last_name,
salary
FROM (
SELECT d.department_name,
e.employee_id,
e.last_name,
e.salary,
AVG(e.salary) OVER () AS avg_salary,
STDDEV(e.salary) OVER () AS stddev_salary
FROM hr.employees e
JOIN hr.departments d
on e.department_id = d.department_id
)
WHERE salary BETWEEN avg_salary - stddev_salary
AND avg_salary + stddev_salary;

Find the number of employees in each department using rollup

so i use code like this:
select count(*) as count, d.department_name
from employees e inner join departments d on e.department_id = d.department_id
group by d.department_name;
but I want to add a rollup function, how do I do it?
Like this:
SELECT COUNT (*) AS COUNT, d.department_name
FROM employees e
INNER JOIN departments d ON e.department_id = d.department_id
GROUP BY ROLLUP (d.department_name);

Select EVERY department and number of employees with salary higher than 10000

I need to select every department name and number of employees earning 10000 or more. That's my code.
SELECT d.department_name, COUNT(e.employee_id)
FROM hr.employees e
JOIN hr.departments d ON d.department_id=e.department_id WHERE e.salary > 10000
GROUP BY d.department_name;
It shows only departments which contains employees earning 10000 but I also need rest of departments with number 0 or - in column COUNT(e.employee_id). Can you help me?
You can do conditional aggregation. The idea is to not put the condition on employee salary in the join, but instead it in a conditional sum:
select
d.department_name,
sum(case when e.salary > 10000 then 1 else 0 end) cnt_high_salaries
from hr.department d
inner join hr.employee e on d.department_id = e.department_id
group by d.department_id, d.department_name
I think you just need outer join in your original query.
SELECT d.department_name,
COUNT(e.employee_id)
FROM hr.departments d
LEFT JOIN hr.employees e
ON d.department_id=e.department_id
and e.salary > 10000
GROUP BY d.department_name;
Is this what you are looking for?
SELECT d.department_name, COUNT(e.employee_id) FROM hr.employees e
JOIN hr.departments d ON d.department_id=e.department_id WHERE d.department_id in
(SELECT distinct e.department_id from employees e WHERE e.salary > 10000)
GROUP BY d.department_name;

Invalid Number Error when Using Non-Numerical Values

I have 2 tables, Departments and Employees. I want to display the department_id, department_name, and the number of employees in any department that has fewer than 4 employees.
Here's the code that I'm using (I use SQL developer, btw):
select d.department_id, d.department_name, count(e.last_name)
from departments d, employees e
where e.last_name < 4
group by d.department_id, d.department_name;
However, I'm getting a invalid number error. What is the correct way to do this?
Something like this would make more sense:
SELECT d.department_id,
d.department_name,
COUNT(*) AS numEmployees
FROM departments d
INNER JOIN employees e
ON d.department_id = e.department_id
GROUP BY d.department_id,
d.department_name
HAVING COUNT(*) < 4

I have a issue in executing the below database query

I have an issue in executing the below database query.
I am using Oracle 11g Enterprise Edition
Query 1:
SELECT d.department_id, max(salary), min(salary), avg(salary), count(*) no_of_employees
FROM departments d, employees e
WHERE e.department_id = d.department_id
GROUP BY d.department_id
Result: successful output
Query 2:
SELECT d.department_id, d.department_name, max(salary), min(salary), avg(salary), count(*) no_of_employees
FROM departments d, employees e
WHERE e.department_id = d.department_id
GROUP BY d.department_id
Result:
ORA-00979: not a GROUP BY expression
Can anybody help me out with this issue?
Please let me know what is wrong with this expression.
you must also group by department_name
You need to GROUP BY all the columns that you don't have an aggregation function (MAX, COUNT, etc). Therefore:
select d.department_id
, d.department_name
, max(salary), min(salary), avg(salary) , count(*) no_of_employees
from departments d, employees e
where e.department_id = d.department_id
group by d.department_id, d.department_name;
But you should also consider doing an ANSI join instead:
select department_id
, department_name
, max(salary), min(salary), avg(salary) , count(*) no_of_employees
from departments
join employees USING (department_id)
group by department_id, department_name;