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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.