Reputation: 61
This is my SQL problem. My SQL table "Employer" has 3 columns: EmployerName, Salary, WorkPosition(eg. Worker, Developer, Manager). So how can I show all the Employers whose salary is higher than the average salary of all the one working in the same position.
I did it as get the values for each position and show out all of those by using UNION. It worked, but seems not to be a good solution.
(Select Employername
From Employer
Where WorkingPosition = 'Worker'
and Salary > (Select avg(Salary) from Employer
Where WorkingPosition = 'Worker'))
UNION
(Select Employername
From Employer
Where WorkingPosition = 'Developer'
and Salary > (Select avg(Salary) from Employer
Where WorkingPosition = 'Developer'))
UNION
(Select Employername
From Employer
Where WorkingPosition = 'Manager'
and Salary > (Select avg(Salary) from Employer
Where WorkingPosition = 'Manager'))
Thanks
Upvotes: 2
Views: 70
Reputation:
You didn't state your DBMS, the following is ANSI SQL.
It will first calculate the averages once for all working positions you are interested in. As that result is quite small it is very likely that the database server can keep that in memory. So the subsequent comparisons in the outer (final) query don't need to re-compute the average each time (of course this also depends on the DBMS being used)
with avg_sales as (
Select WorkingPosition, avg(Salary) as avg_salary
from Employer
Where WorkingPosition in ('Worker', 'Developer', 'Manager')
group by WorkingPosition
)
Select emp.Employername
From Employer emp
where Salary > (select avg_salary
from avg_sales s
where s.WorkingPosition = emp.WorkingPosition)
and WorkingPosition in ('Worker', 'Developer', 'Manager');
Upvotes: 2
Reputation: 4899
Get them all at once:
Select e1.Employername
From Employer e1
Where
e1.Salary > (Select avg(e2.Salary) from Employer e2
Where e2.WorkingPosition = e1.WorkingPosition))
Upvotes: 1
Reputation: 116498
You should be able to join on a derived table with the averages.
The best way to solve this type of problem is to break it down into parts. The first part being how to get the average salary for each position. You should be able to GROUP
to get this:
SELECT AVG(Salary) AS AvgSalary, WorkingPosition
FROM Employer
GROUP BY WorkingPosition
Then you can join on this table - now you have each employee correlated with the average salary in their position:
SELECT *
FROM Employer
INNER JOIN
(
SELECT AVG(Salary) AS AvgSalary, WorkingPosition
FROM Employer
GROUP BY WorkingPosition
) Averages ON Employer.WorkingPosition = Averages.WorkingPosition
Finally, add the condition:
SELECT Employer.Employername
FROM Employer
INNER JOIN
(
SELECT AVG(Salary) AS AvgSalary, WorkingPosition
FROM Employer
GROUP BY WorkingPosition
) Averages ON Employer.WorkingPosition = Averages.WorkingPosition
WHERE Employer.Salary > Averages.AvgSalary
If you are more comfortable working with a subquery in the WHERE
clause, you can do this as well. I would imagine both should perform rather similarly:
SELECT Employername
FROM Employer
WHERE Salary > (SELECT AVG(Salary)
FROM Employer AS Averages
WHERE Employer.WorkingPosition = Averages.WorkingPosition)
Upvotes: 2
Reputation: 40499
Select Employername From Employer
Where
( WorkingPosition = 'Worker' and Salary >
(Select avg(Salary) from Employer Where WorkingPosition = 'Worker')
)
or
( WorkingPosition = 'Developer' and Salary >
(Select avg(Salary) from Employer Where WorkingPosition = 'Developer')
)
or
( WorkingPosition = 'Manager' and Salary >
(Select avg(Salary) from Employer Where WorkingPosition = 'Manager')
)
Or
select o.employername
from employer o
where
o.salary > (select avg(i.salary)
from employer i
where i.workingposition = o.workingposition
)
and
o.workingposition in ('Worker', 'Developer', 'Manager')
Upvotes: 1