从表中选择记录,其中字段不在MySql中不同表的左连接中

时间:2013-12-30 17:21:54

标签: mysql sql

在任何合理的运行时间努力获得这个。我有三张桌子:

temp_company

  • id(PRIMARY KEY),数字(KEY),s_code(KEY)

公司

  • id(PRIMARY KEY),数字(KEY)

company_scode

  • company_id(关于company_id和代码的UNIQUE),代码(KEY) code_description表的代码和代码之间也有一个外键。 company_id和公司表中的id之间还有一个外键

我需要将temp_company表与number字段上的company表匹配,然后我想检查company_scode表中公司是否存在临时表中的s_code,如果它没有选择那个行。

到目前为止,我有:

SELECT temp_company.s_code 
FROM temp_company
WHERE temp_company.s_code NOT IN 
(SELECT code
FROM company
LEFT JOIN company_scode ON company.id = company_scode.company_id
WHERE 
company.number = temp_company.number
)

但这非常慢,我希望有一种更好的方法来选择每个temp_company记录,其中s_code在公司和company_scode之间的多对多关系中不存在。

*更新 *

感谢Loc和Ollie的答案,这些仍然需要很长时间(我离开Ollie已经8个小时了,而且还在继续)。

就索引而言,我已在上面更新了信息。我已经将下面的解释放在了两个答案中,试图揭开一些亮点,希望能更快地实现这一点。

解答奥利的答案:

| id | select_type        | table      | type  | possible_keys | key        | key_len | ref                   | rows    | extra                    |
+----+--------------------+------------+-------+---------------+------------+---------+-----------------------+---------+--------------------------+
| 1  | PRIMARY            | tc         | ALL   | (NULL)        | (NULL)     | (NULL)  | (NULL)                | 3216320 |                          |
+----+--------------------+------------+-------+---------------+------------+---------+-----------------------+---------+--------------------------+
| 1  | PRIMARY            | <derived2> | ALL   | (NULL)        | (NULL)     | (NULL)  | (NULL)                | 2619433 | Using where; Not exists  |
+----+--------------------+------------+-------+---------------+------------+---------+-----------------------+---------+--------------------------+
| 2  | DERIVED            | s          | index | company_id    | code       | 62      | (NULL)                | 2405379 |              Using index |
+----+--------------------+------------+-------+---------------+------------+---------+-----------------------+---------+--------------------------+
| 2  | DERIVED            | c          | eq_ref| PRIMARY       | PRIMARY    | 4       | mydbname.s.company_id |    1    |                          |
+----+--------------------+------------+-------+---------------+------------+---------+-----------------------+---------+--------------------------+

解答Loc的答案:

| id | select_type        | table | type  | possible_keys | key        | key_len | ref           | rows    | extra                    |
+----+--------------------+-------+-------+---------------+------------+---------+---------------+---------+--------------------------+
| 1  | PRIMARY            | tc    | ALL   | (NULL)        | (NULL)     | (NULL)  | (NULL)        | 3216320 | Using where              |
+----+--------------------+-------+-------+---------------+------------+---------+---------------+---------+--------------------------+
| 2  | DEPENDENT SUBQUERY | c     | index | (NULL)        | number     | 63      | (NULL)        | 3189756 | Using where; Using index |
+----+--------------------+-------+-------+---------------+------------+---------+---------------+---------+--------------------------+
| 2  | DEPENDENT SUBQUERY | cc    | ref   | company_id    | company_id | 4       | mydbname.c.id |    1    | Using where; Using Index |
+----+--------------------+-------+-------+---------------+------------+---------+---------------+---------+--------------------------+

3 个答案:

答案 0 :(得分:1)

测试这个:

SELECT tc.*
FROM temp_company tc
WHERE NOT EXISTS
(
    SELECT 1
    FROM company c LEFT JOIN company_scode cc ON c.id = cc.company_id
    WHERE c.number = tc.number
)

答案 1 :(得分:1)

这种方式可能比嵌套的SELECT快得多。

SELECT tc.id, tc.number, tc.s_code
  FROM temp_company AS tc
  LEFT JOIN (
      SELECT s.code AS company_scode,
             c.id
        FROM company AS c
        JOIN company_scode AS s ON c.id = s.code      
      ) AS existing_company 
           ON  (     tc.scode = existing_company.company_scode
                 AND tc.id = existing_company.id)
  WHERE existing_company.company_scode IS NULL 

这可以通过运行返回(id,scode)列表的子查询来实现。然后它将它连接到temp_company表并使用IS NULL查找仅出现在连接左侧的项目。

答案 2 :(得分:0)

最后,我将这一点降低到大约1分钟的可管理时间,其中包括以下内容:

CREATE TEMPORARY TABLE tc AS
(SELECT company.id AS cid, temp_company.scode AS tcode
FROM temp_company
INNER JOIN company ON temp_company.number = company.number
WHERE temp_company.scode IS NOT NULL AND temp_company.scode != "")

CREATE TEMPORARY TABLE rc AS
(SELECT tc.cid as cid FROM tc
LEFT JOIN company_scode ON tc.cid = company_scode.company_id
WHERE tc.tcode = company_scode.code)

SELECT * FROM tc
WHERE tc.cid NOT IN (SELECT cid FROM rc)

我宁愿不使用临时表,所以如果有人在类似或更快的时间内发布解决方案,那么我很乐意更新答案。