What's wrong with my simple SQL query? - sql

What is wrong with this SQL query?
SELECT
department_id, MAX(AVG(SALARY))
FROM
EMPLOYEES
GROUP BY
department_id;
It shows not a single-group group function

2 Aggregate functions in one Query can not be done, you should use a Subquery to achieve your result.
I've not possibility to test it right now so no guarantees on this query but you may get an idea.
select max (avg_salary)
from (select department_id, avg(SALARY) AS avg_salary
from EMPLOYEES
group by department_id);
The inner query selects deparment_id and average salary.
Avarage salary is selected using the alias avg_salary using the AS statement.
The outer query selects the maximum of avg_salary-
That's maybe not a complete solution to your problem and as I said, not tested so no guarantees, but you should have an idea now how to start. ;-)

You cant have more than one aggregate functions in one query. try this one
select dept, max(average) over (partition by dept)
from (SELECT department_id dept,
(AVG(SALary) OVER (PARTITION BY department_id)) average
FROM employees);

Alternative 1, double GROUP BY:
SELECT department_id, AVG(SALARY)
FROM EMPLOYEES
GROUP BY department_id
HAVING AVG(SALARY) = (select max(avg_sal)
from (select avg(salary) as avg_sal
from EMPLOYEES
group by department_id))
Will return both department_id's if there's a tie!
Alternative 2, use a cte (common table expression):
with
(
SELECT department_id, AVG(SALARY) as avg_sal
FROM EMPLOYEES
GROUP BY department_id
) as cte
select department_id, avg_sal
from cte
where avg_sal = (select max(avg_sal) from cte)
This too will return both department_id's if there's a tie!

Related

Subquery with multiple averages

I've been struggling with a problem that goes something like this, "Find all employees with a salary greater than the average salary of their department." My sql subquery lumps all the departments salaries together to make one average salary but I need a way to get the each individual department's average salary.
My sql statement looks like this.
SELECT EmployeeName
FROM dbo.EMP
WHERE Salary > (
SELECT AVG(Salary)
FROM dbo.EMP
)
GROUP BY DeptNo
here is quick variant:
select EmployeeName
from
dbo.EMP as a
inner join
(
SELECT DeptNo, AVG(Salary) as avgSalary
FROM dbo.EMP
GROUP BY DeptNo
) as b
on (a.DeptNo=b.DeptNo and a.Salary > b.avgSalary)
You can just finish off that subquery to make it a correlated subquery:
SELECT EmployeeName
FROM dbo.EMP as t1
WHERE Salary > (
SELECT AVG(Salary)
FROM dbo.EMP
WHERE dbo.EMP.DeptNo = t1.DeptNo
)
Alternatively you could use Window Functions:
SELECT
EmployeeName,
CASE WHEN Salary > AVG(Salary) OVER (PARTITION BY DeptNo) Then 'X' END as [HigherThanAverage]
FROM dbo.EMP
That will give you all employees and an indicator if their salary is higher than their department's average, which you could filter out later on. I figured I'd stick this in here since it gives you some options as the scale of your query grows.

MAX and GROUP BY - SQL

I'm working on Oracle SQL and HR database, I'm trying to select maximum salary in department like this:
SELECT MAX(salary), department_id
FROM employees GROUP BY department_id;
It works fine, but I want to know >who< is earning the most, so I simply change query this way:
SELECT first_name, last_name, MAX(salary), department_id
FROM employees GROUP BY department_id;
And it's wrong. Could you help me, please?
The most efficient way to do this sort of analysis is generally to use analytic functions (window functions). Something like
SELECT first_name,
last_name,
salary,
department_id
FROM (SELECT e.*,
rank() over (partition by department_id
order by salary desc) rnk
FROM employees e)
WHERE rnk = 1
Depending on how you want to handle ties (if two people in the department are tied for the maximum salary, for example, do you want both people returned or do you want to return one of the two arbitrarily), you may want to use the row_number or dense_rank functions rather than rank.
Create a view:
create view max_salary as select max(salary), department_id from employees group by department_id
Then create a query:
select first_name, last_name, salary, department_id
from employees a, max_salary b
where a.department_id = b.department_id
and a.salary = b.salary

Select data using condition from AVG expression in HR table

I try to learn mysql oracle database, I want to show average salary from table employee group by department_id and where average salary is like '%0'.
here is my query
select department_id, AVG(salary) as "Pay Salary per dept"
from employees
where department_id is not null and AVG(salary) like '%0'
group by department_id order by department_id
what's right query to replace
AVG(salary) like '%0' ?
Thanks
Use MOD function instead of LIKE.
where MOD(salary,10)=0
query
select t.dept_id,t.Pay_Salary_per_dept
from
(
select dept_id, AVG(salary) as Pay_Salary_per_dept
from employee
where dept_id is not null
group by dept_id
)t
where mod(t.Pay_Salary_per_dept,10)=0
order by t.dept_id;
Fiddle demo here
To filter the result of aggregated functions there is the HAVING clause in SQL.
You may write it direct without a subquery as follows:
select dept_id, AVG(salary) as Pay_Salary_per_dept
from employee
where dept_id is not null
group by dept_id
having mod(AVG(salary),10)=0
;

Oracle - How to return average from a subquery?

I need to select employees having salary bigger than the average salary grouped by departments.
SELECT * FROM employees
WHERE salary > (SELECT AVG(salary), department_id FROM employees GROUP BY department_id)
It's failing because It returns me 2 columns.
I have tried with this query:
SELECT * FROM employees
HAVING salary > AVG(salary)
GROUP BY (department_id)
Now i am getting error message: ORA-00979: not a GROUP BY expression
The simplest cross-database approach would be to use a JOIN:
SELECT employees.*
FROM employees
JOIN ( SELECT department_id, AVG(salary) avgSalary
FROM employees
GROUP BY department_id) departmentSalaries
ON employees.department_id = departmentSalaries.department_id
AND employees.salary > departmentSalaries.avgSalary
The most efficient approach for Oracle would be to use an analytic function (aka window function):
SELECT * FROM (
SELECT e.*, AVG(e.salary) OVER ( PARTITION BY e.department_id ) as avgSalary
FROM employees e) t
WHERE salary > avgSalary

How to find maximum avg

I am trying to display the maximum average salary; however, I can't seem to get it to work.
I can get a list of the average salaries to display with:
select worker_id, avg(salary)
from workers
group by worker_id;
However, when I try to display a list of the maximum average salary with:
select max (avg(salary))
from (select worker_id, avg(salary)
from workers
group by worker_id);
it doesn't run. I get an "invalid identifier" error. How do I use the average salary for each worker to find the maximum average for each worker?
Thanks.
Columns resulting from aggregate functions (e.g. avg) usually get arbitrary names. Just use an alias for it, and select on that:
select max(avg_salary)
from (select worker_id, avg(salary) AS avg_salary
from workers
group by worker_id) As maxSalary;
select worker_id, avgsal
from
(
select worker_id, avg(salary) as avgsal
from workers
group by worker_id
)
where avgsal=(select max(avgsal)
from (select worker_id, avg(salary) as avgsal
from workers group by worker_id))
This will display the highest average along with worker id
As explained here
you can use
SELECT worker_id, AVG(salary)
FROM workers
GROUP BY worker_id
HAVING AVG(salary) = (SELECT MAX(AVG(salary)) FROM workers GROUP BY worker_id)
select worker_id, avg(salary)
from workers
group by worker_id
having avg(salary) = (select max(avgsal) from
(select worker_id, avg(salary) as avgsal
from workers
group by worker_id));
This should also work i guess
You can fix the query by adding a column alias to the column within the sub-query, like so:
select max(avg_salary)
from (select worker_id, avg(salary) avg_salary
from workers
group by worker_id);
However, if worker_id uniquely identifies records on the workers table, this is functionally equivalent to (can be simplified to):
select max(salary) from workers;
using WITH clause it can be done as
with averagesal as (
select dept_id d_id, avg(sal) avgsal from emp_details group by dept_id)
select * from averagesal where avgsal = (select max(avgsal) from averagesal);
select max(a.high)Avg_highest_salary,
e.dept
from (
select avg(salary) high,dept from emp group by dept) a,
emp e
where a.dept = e.dept
group by e.dept
order by max(a.high) desc
It will show the high Average highest salary first with dept
If you don't want to show the Salary with Dept then you can use this
select max(avg(salary)) max_avg_salary
from emp
group by dept;
select Dep_name
from
(
select Dep_name , avg(Salary) as avgsal
from salary
group by Dep_name
) sal1
where avgsal=(select max(avgsal)
from (select Dep_name , avg(salary) as avgsal
from salary group by Dep_name) sal2)
You should try the following approach:
select avg(salary) as max_avg_salary from Salaries group by emp_no order by avg(salary) desc limit 1;
https://stackoverflow.com/a/8050885/12190487 shows the folllowing error
ER_DERIVED_MUST_HAVE_ALIAS: Every derived table must have its own alias
Use alias for the new formed column you are selecting from
select max(avg_salary)
from (select worker_id, avg(salary) AS avg_salary
from workers
group by worker_id) as avg ;
This worked out for me.
from (select avg(salary) AS avg_salary
from employees
group by Name) AS T;
You can in this way that the first row is sorted in descending based on average find
select top 1 worker_id, avg(salary) as avgsalary
from workers
group by worker_id
order by avgsalary desc
select * from (select avg(sal) over (partition by deptno ) avrg,deptno from emp
order by avrg desc) where rownum<2;
Try the above one.
Here is how to also get the worker_id, inspired by previous answers:
SELECT worker_id, MAX(avg_salary)
FROM (SELECT worker_id, AVG(salary) AS avg_salary
FROM workers
GROUP BY worker_id);
You can also do this with a single select statement (combining both max and avg) like this
select max(avg(salary)) max_avg_salary
from workers
group by worker_id;