简体   繁体   中英

Convert Sub-query into Joins

I am trying to convert below query via Joins,

SELECT DISTINCT req.*
FROM request req
WHERE (req.user_id IN (
            SELECT id from user where id in (SELECT user_id FROM team_member team WHERE team.team_id IN ('344', '723')) and user.active = 1
)
OR req.user_id IN (
  SELECT id from user where id in (SELECT approved_employee_id from approver where approver_id = '269') and user.active = 1
))
   AND req.status = 'pending';

returns 124 records.

I have wrote below query via joins but doesn't work,

SELECT DISTINCT req.*
FROM request req
  LEFT JOIN user u ON u.id = req.user_id AND u.active = 1
  LEFT JOIN team_member team ON team.user_id = u.id AND team.team_id IN ('344', '723')
  LEFT JOIN approver app ON app.approver_id = u.id AND app.approver_id = '269'
AND req.status = 'pending';

returns more than 500 records.

two issue with this joins, it includes those requests too where status is not pending.

Below is the schema

I have below tables

tbl_approver = 
id, 
approver_id (FK tbl_user), 
approver_team_id (FK tbl_team), 
approved_employee_id (FK tbl_user)

tbl_team_mambers = 
id, 
team_id (FK), 
user_id (FK)

tble_user = 
id, 
email, 
username
active


tbl_request = 
id, 
user_id, 
status
  • Teams Members : A user is a member of multiple teams.
  • Approver :
    • For each team there is an approver, who is also the member of that team.
    • there can be direct approver of an employee regardless of team.
  • request : inventory requests by the user

Note : as an approver, i can be member of many teams but only approver of some team. or some employee too.

Query wanted : as an approver i want all request of my teams whom i am approver.

For correct results of join 's you need to any joined "table" return only one row for user_id. And do not use left if needed only rows existing in all tables.

SELECT req.*
  FROM request req
  JOIN user ON user.id=req.user_id
  JOIN (
        SELECT distinct approved_employee_id as user_id from approver where approver_id = '269'
         UNION
        SELECT distinct user_id FROM team_member team WHERE team.team_id IN ('344', '723')
       ) A ON req.user_id=A.user_id
 where user.active = 1
   AND req.status = 'pending';

Or, if needed only "real table":

SELECT DISTINCT req.*
  FROM request req
  JOIN user u ON u.id = req.user_id AND u.active = 1
  LEFT JOIN team_member team ON team.user_id = u.id AND team.team_id IN ('344', '723')
  LEFT JOIN approver app  ON app.approver_id = u.id AND app.approver_id = '269'
 WHERE req.status = 'pending'
   AND (team.user_id is not null OR app.approver_id is not null)

Watch the LEFT JOIN syntax, here's the visual expression of joins

SELECT DISTINCT req.*
FROM request req
LEFT JOIN user u ON u.id = req.user_id AND u.active = 1
...

This will select all distinct records from request , and JOIN them to user. The join_condition after ON will only affect the join relation.

If there is no matching row for the right table in the ON or USING part in a LEFT JOIN, a row with all columns set to NULL is used for the right table.

Join syntax from Mysql Documentation

If you really want to use LEFT JOIN to filter all record from request , consider moving the condition_expr to WHERE

SELECT DISTINCT req.*
FROM request req
LEFT JOIN user u ON u.id = req.user_id
...
WHERE u.active = 1
AND ...

If you only need request that satisfies the join condition to user, you should consider use Join rather than LEFT JOIN .

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