0

I just need a little help about SQL queries

Here's the situation

ID   FIRST_NAME LAST_NAME  START_DAT END_DATE  SALARY     CITY       DESCRIPTION
---- ---------- ---------- --------- --------- ---------- ---------- ---------------
01   Jason      Martin     25-JUL-96 25-JUL-06 1234.56    Toronto    Programmer
02   Alison     Mathews    21-MAR-76 21-FEB-86 6661.78    Vancouver  Tester
03   James      Smith      12-DEC-78 15-MAR-90 6544.78    Vancouver  Tester
04   Celia      Rice       24-OCT-82 21-APR-99 2344.78    Vancouver  Manager
05   Robert     Black      15-JAN-84 08-AUG-98 2334.78    Vancouver  Tester
06   Linda      Green      30-JUL-87 04-JAN-96 4322.78    New York   Tester
07   David      Larry      31-DEC-90 12-FEB-98 7897.78    New York   Manager
08   James      Cat        17-SEP-96 15-APR-02 1232.78    Vancouver  Tester

8 rows selected.

SQL> -- GROUP BY clause and AVG() function

SQL> SELECT city, AVG(salary)
2 FROM employee
3 GROUP BY city;


CITY AVG(SALARY)
---------- -----------
New York 6110.28

Toronto 1234.56

Vancouver 3823.78

The problem is I can't find a way to extract those names having higher salaries from each avg(salary) for city

Example:

Vancouver has avg(salary) of 3823.78 so I should get the name of 2 people: alison and james because they have higher salary than the avg(salary) of new york

For now I only go to this query but not working

select FIRST_NAME,SALARY,CITY 
from employee 
where SALARY > (  select avg(SALARY) 
                  from employee 
                  group by CITY
                );

it tells me that subquery return more than 1 value

Hope someone can help me

1 Answer 1

2

Your query is returning more than one value. To restrict it to one value, you need a condition on city:

select FIRST_NAME,SALARY,CITY
from employee e
where SALARY > (select avg(SALARY) 
                from employee e2 
                where e2.city = e.city 
                group by CITY);

This is called a correlated subquery. You can also write it as a join, which is the syntax that I would use. The group by CITY is, strictly speaking, unnecessary, but I think it makes the intention of the subquery clearer.

You can rewrite this as a join by doing:

select e.FIRST_NAME, e.SALARY, e.CITY
from employee e join
     (select city, avg(salary) as avgSalary
      from employee
      group by city
     ) ec
     on e.city = ec.city
where e.salary > ec.avgSalary

Or, what would be my favorite way . . .

select e.FIRST_NAME, e.SALARY, e.CITY
from (select e.*,
             avg(salary) over (partition by city) as avgSalary
      employee e
     ) e
where e.salary > e.avgSalary
Sign up to request clarification or add additional context in comments.

3 Comments

A join is not necessarily a replacement for a co-related sub-query.
@a_horse_with_no_name . . . A join and group by can replace many correlated subqueries. Not all, but most that you see in practice.
nice bro the first one is working-the other 2 seems difficult:D tyvm

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.