将不在查询中的mysql写为join

时间:2016-01-28 20:16:56

标签: mysql

我有两个表vtiger_crmentity和vtiger_crmentityrel(来自开源项目vtiger)。

vtiger_crmentity

+--------------+--------------+------+-----+---------+-------+
| Field        | Type         | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+-------+
| crmid        | int(19)      | NO   | PRI | NULL    |       |
| smcreatorid  | int(19)      | NO   | MUL | 0       |       |
| smownerid    | int(19)      | NO   | MUL | 0       |       |
| modifiedby   | int(19)      | NO   | MUL | 0       |       |
| setype       | varchar(30)  | NO   |     | NULL    |       |
| description  | text         | YES  |     | NULL    |       |
| createdtime  | datetime     | NO   |     | NULL    |       |
| modifiedtime | datetime     | NO   |     | NULL    |       |
| viewedtime   | datetime     | YES  |     | NULL    |       |
| status       | varchar(50)  | YES  |     | NULL    |       |
| version      | int(19)      | NO   |     | 0       |       |
| presence     | int(1)       | YES  |     | 1       |       |
| deleted      | int(1)       | NO   | MUL | 0       |       |
| label        | varchar(255) | YES  | MUL | NULL    |       |
+--------------+--------------+------+-----+---------+-------+

vtiger_crmentityrel

+-----------+--------------+------+-----+---------+-------+
| Field     | Type         | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+-------+
| crmid     | int(11)      | NO   |     | NULL    |       |
| module    | varchar(100) | NO   |     | NULL    |       |
| relcrmid  | int(11)      | NO   |     | NULL    |       |
| relmodule | varchar(100) | NO   |     | NULL    |       |
+-----------+--------------+------+-----+---------+-------+

我正在尝试获取crmentityrel表中不存在的联系人列表(在relcrmid列中是特定的)。我可以通过子查询执行此操作,但是大约需要2分钟才能完成(每个表中大约有2万条记录)。

我试图将查询转换为连接,但我肯定做错了,因为我一直得到错误的值(与我知道的子查询相比)。

非常感谢任何帮助。如果您需要我方提供任何详细信息,请告诉我

编辑 - 我的工作查询(带子查询)是 -

SELECT crmid, label from vtiger_crmentity 
WHERE deleted = 0 and setype="Contacts" 
 and crmid not in (select relcrmid from vtiger_crmentityrel 
where relmodule="Contacts")

1 个答案:

答案 0 :(得分:3)

要将not in转换为join,我们的想法是使用left joinwhere

SELECT c.crmid, c.label
FROM vtiger_crmentity  c left join
     vtiger_crmentityrel cr
     on c.crmid = cr.relcrmid and relmodule = 'Contacts'
WHERE c.deleted = 0 and c.setype = 'Contacts' and cr.relcrmid is null;

我应该指出,上述内容并非完全等同于。如果子查询返回单个NOT IN值,则NULL不返回任何行。上述行为更为直观。

由于NOT IN具有NULL值的行为,NOT EXISTS是更好的选择。此外,它通常也有更好的表现:

SELECT crmid, label 
FROM vtiger_crmentity c
WHERE deleted = 0 and setype = 'Contacts' AND
      NOT EXISTS (SELECT relcrmid 
                  FROM vtiger_crmentityrel  cr
                  WHERE cr.relmodule = 'Contacts' and cr.relcrmid = c.crmid
                 );