Consider the query:
Find all departments where the total salary is greater than the average of the total salary at all departments
with dept_total (dept_name, value) as
(
select dept_name, sum(salary)
from instructor
group by dept_name
),
dept_total_avg(value) as
(
select avg(value)
from dept_total
)
select dept_name
from dept_total, dept_total_avg
where dept_total.value >= dept_total avg.value;
Rewrite this query without using the with construct.
The query is based on University schema which is provided by The database system concept by Korth. I assume I need to consider only the instructor table to find the answer of the query.
Instructor (ID, name, dept_name, salary)
I can found the average of total salary of all dept
SELECT AVG(salary) GROUP BY dept_name;
Then I lost. I did not find the way to proceed.
I found that. But I am looking for more explanation as I cannot understand it from this link.
Thank you for help.
Here's a few ways to do it in a mySQL version that doesn't support CTEs (I'm assuming that's why they are having you rewrite the query to omit the with). Also, you are calculating the average salary by department, but the question is asking to find the average TOTAL salary of each department, then return the ones that fall above that.
https://dbfiddle.uk/?rdbms=mysql_5.5&fiddle=fefea829cff3e20aea93634f9a4114d6
With a subquery:
SELECT dept_name
FROM (
SELECT dept_name, sum(salary) as salaries
FROM instructor GROUP BY dept_name
) d
WHERE salaries > (
SELECT avg(salaries) as avgSalaries FROM (
SELECT dept_name, sum(salary) as salaries
FROM instructor GROUP BY dept_name
) z
)
With a join:
SELECT dept_name
FROM (
SELECT dept_name, sum(salary) as salaries
FROM instructor GROUP BY dept_name
) d
CROSS JOIN (
SELECT avg(salaries) as avgSalaries FROM (
SELECT dept_name, sum(salary) as salaries
FROM instructor GROUP BY dept_name
) z
) avgs
WHERE salaries > avgs.avgSalaries
With a session variable (this is deprecated in later versions, but does still work):
SELECT avg(salaries) INTO #avg FROM (
SELECT dept_name, sum(salary) as salaries
FROM instructor GROUP BY dept_name
) z;
SELECT #avg;
SELECT dept_name
FROM instructor GROUP BY dept_name
HAVING sum(salary) > #avg;
All good techniques to understand.
Read your last question and found that you are using mysql5.8, then you can use the analysis function
select distinct t1.dept_name
from (
select t1.*,
sum(salary) over(partition by dept_name) val,
sum(salary) over() / count(distinct dept_name) over() avg
from Instructor t1
) t1
where t1.val > t1.avg
Related
i want to show the salaries less than the largest number in the table
create table instructor(
ID number not null ,
name varchar(20) ,
dept_name varchar(25),
salary number,
primary key (ID)
);
insert into instructor values('10101', 'sirinvasan' , 'comp csi' , '65000');
insert into instructor values('12121', 'wu' , 'finance' , '90000');
insert into instructor values('15151', 'mozart' , 'music' , '40000');
insert into instructor values('22222', 'einstein' , 'physics' , '95000');
insert into instructor values('32343', 'el said' , 'history' , '60000');
i tried using
select distinct T.salary
from instructor as T , instructor as S
where T.salary < S.salary
but it gives me this error ORA-00933: SQL command not properly ended
You can do it in a single table scan using analytic functions:
SELECT salary
FROM (
SELECT DISTINCT
salary,
DENSE_RANK() OVER (ORDER BY salary DESC) AS rnk
FROM instructor
)
WHERE rnk > 1
Or, if you want to use a sub-query:
SELECT DISTINCT
salary
FROM instructor
WHERE salary NOT IN (SELECT MAX(salary) FROM instructor);
db<>fiddle here
Try this
Select salary from table where salary < (Select
max(salary) from table)
There are many ways to do this. Here is another one.
with a as (
select salary
, max(salary) over () as maxsalary
from instructor
)
select distinct salary
from a
where salary < maxsalary
In the name of completeness, here is another viable answer:
SELECT DISTINCT i.salary
FROM instructor i
ORDER BY i.salary DESC
OFFSET 1 ROW;
I actually like the simplicity of this one. It is just ordering the query and skipping the first row. No analytic functions necessary.
DBFiddle Here: (LINK)
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;
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!
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
I have a table containing attributes Id, Emp_name, dept_name, salary. Now i want to write an SQL query that will give me the dept_name value for which the overall salary of all employees belonging to that department is the highest, i.e dept for which sum of salaries of all its employees is the highest...? If there is any similar question with answer on stackoverflow, please suggest.. I dint find one. Thanks :)
I tried group by with sum() function, but i could not get how to find the maximum and compare it with sum.
Can you do
SELECT TOP 1 dept_name FROM table GROUP BY dept_name ORDER BY SUM(salary) DESC
Seems like a textbook example for GROUP BY:
select dept_name, total_salary from (
Select dept_name, sum(salary) as total_salary
from my_table
group by dept_name
) order by total_salary desc
try this:
select top 1 dept_name from myTable group by dept_name order by sum(salary) desc
SELECT dept_name FROM table
GROUP BY dept_name
ORDER BY SUM(salary) DESC
LIMIT 1
And you would also better have you departments in another table linked to the first table via foregn keys. Just a note.
I don't know exactly know your requirements, but perhaps there is another point to be considered: Two (or more) departments could have the same sum of salary.
I have not tested the query, but this should give you all departments which have the maximum some of salary:
select dept_name FROM table_name GROUP BY dept_name HAVING SUM(salary)=(select MAX(sum_salary) FROM (select SUM(salary) AS sum_salary FROM table_name GROUP BY dept_name))