如何在MySQL中将NOT IN子句转换为左外连接

时间:2013-06-11 20:59:05

标签: mysql left-join

我正在尝试将查询从NOT IS子句转换为左外连接以获得更好的性能。

以下是我的查询完美无缺

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

所以我想将它更改为左连接或某种类型的连接,它们将执行相同的查询。 我试过这个,但它不适合我

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

我的第二个查询总是返回任何内容。

我已经尝试了这个查询,这给了我更多的结果,第一个查询所以它不一样

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

2 个答案:

答案 0 :(得分:3)

检查p.status = 2子句中的join,而不是where子句:

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

如果你把它放在where子句中,会加入phone_calls,你会在加入后检查

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

这些陈述可能完全冲突(所有带状态= 2的phone_calls都有id)。

一般来说,你不应该在WHERE子句中加入一个左边的子句(IS NULL / IS NOT NULL除外)

答案 1 :(得分:0)

好奇,但尝试使用NOT EXISTS子句:

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

我认为只有EXPLAIN会揭示哪种技巧更好。通过未选择的列对结果进行排序似乎很奇怪,但这是一个不同的问题。