简体   繁体   中英

MySQL join with a subquery

I have three tables and am trying to get info from two and then perform a calculation on the third and display all the results in one query.

The (simplified) tables are:

table: employee_work

employee_id name
1 Joe
2 Bob
3 Jane
4 Michelle

table: carryover

employee_id days
1 5
2 10
3 3

table: timeoff

employee_id time_off_type days
1 Carryover 2
1 Leave 3
1 Carryover 1
2 Sick 4
2 Carryover 4
3 Leave 1
4 Sickness 4

The results I would like are:

employee_id, carryover.days, timeoff.days
1 5 3
2 10 4
3 3 0

However when I run the query, whilst I get the correct values in columns 1 and 2, I get the same number repeated in the third column for all entries.

Here is my query:

Select
  employee_work.employee_id,
  carryover.carryover,
  (SELECT SUM(days) FROM timeoff WHERE timeoff.time_off_type = 'Carryover' 
  AND timeoff.start_date>='2013-01-01') AS taken
From
  carryover Left Join
  employee_work On employee_work.employee_id = carryover.employee_id Left Join
  timeoff On employee_work.employee_id = timeoff.employee_id Left Join
Where
  carryover.carryover > 0
Group By
  employee_work.employee_id

I have tried to group by in the sub query but I then get told "Subquery returns more than one row" - how can I ensure that the sub query is respecting the join so it only looks at each employee at a time so I get my desired results?

The answer to your question is to use a correlated subquery. You don't need to mention the timeoff table twice in this case:

Select
  employee_work.employee_id,
  carryover.carryover,
  (SELECT SUM(days)
   FROM timeoff
   WHERE timeoff.time_off_type = 'Carryover' and
         timeoff.start_date>='2013-01-01' and
         timeoff.employee_id = employee_work.employee_id
  ) AS taken
From
  carryover Left Join
  employee_work On employee_work.employee_id = carryover.employee_id
Where
  carryover.carryover > 0
Group By
  employee_work.employee_id;

An alternative structure is to do the grouping for all employees in the from clause. You can also remove the employee_work table, because it does not seem to be being used. (You can use carryover.employee_id for the id.)

Select co.employee_id, co.carryover, et.taken
From carryover c Left Join
     (SELECT employee_id, SUM(days) as taken
      FROM timeoff
      WHERE timeoff.time_off_type = 'Carryover' and
            timeoff.start_date>='2013-01-01'
     ) et
     on co.employee_id = et.employee_id
 Where c.carryover > 0;

I don't think the group by is necessary. If it is, then you should probably have an aggregation function in the original query.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM