简体   繁体   中英

How can I convert a NOT IN Clause into a left outer join in MySQL

I am trying to convert a query for better performance from a NOT IS clause to a left outer join.

the following is my query which works perfectly

SELECT a.company_code, account_name, legal_name FROM accounts a

WHERE account_id NOT IN (SELECT DISTINCT  account_id FROM phone_calls WHERE status = 2 ) AND account_id >10000

ORDER BY legal_name, account_name, account_id

So I want to change it to a left join or some type of join that will do the same query. I have tried this but it is not working for me

SELECT a.company_code, a.account_name, a.legal_name, p.phone_call_id
FROM accounts AS a
LEFT JOIN phone_calls AS p ON p.account_id = a.account_id

WHERE a.account_id >= 10000 AND p.status = 2 AND p.phone_call_id IS NULL

ORDER BY a.legal_name, a.account_name, a.account_id

my second query returns nothing always.

I have tried this query and this gives me more results that the first query so it is not the same

SELECT a.company_code, a.account_name, a.legal_name, p.phone_call_id
FROM accounts AS a
LEFT JOIN phone_calls AS p ON p.account_id = a.account_id AND p.status = 2 AND a.account_id >= 10000

WHERE p.account_id IS NULL

ORDER BY a.legal_name, a.account_name, a.account_id

put the check for p.status = 2 in the join clause, not in the where clause :

SELECT a.company_code, a.account_name, a.legal_name, p.phone_call_id
FROM accounts AS a
LEFT JOIN phone_calls AS p ON p.account_id = a.account_id AND p.status = 2
WHERE a.account_id >= 10000  
AND p.phone_call_id IS NULL

ORDER BY a.legal_name, a.account_name, a.account_id

If you put it in the where clause, phone_calls will be joined, and you will check after joining

  • that p.status=2
  • that p.phone_call_id IS NULL

these statements are probably in total conflict (all phone_calls with a status = 2 have an id).

And in general, you should not have a clause on a Left joined tabled in the WHERE clause (except IS NULL / IS NOT NULL )

Just curious, but try using a NOT EXISTS clause:

SELECT company_code
     , account_name
     , legal_name 
FROM   accounts a
WHERE  account_id > 10000
   AND NOT EXISTS (
      SELECT 1 
      FROM phone_calls b
      WHERE b.status = 2 
        AND b.account_id = a.account_id
      )
ORDER BY legal_name, account_name, account_id

I think only an EXPLAIN will reveal which is the better technique. Seems strange to ORDER the results by columns not selected, but that's a different question.

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