如何使用 JOIN 而不是 SELECT NOT IN?

How to use JOIN instead of SELECT NOT IN?

我有 2 个表:

例如,我希望找到所有没有租赁合同的客户。

我可以这样做:

SELECT contragent_name 
FROM contragents 
WHERE contragent_id NOT IN (SELECT contragent_id 
                            FROM documents 
                            WHERE document_name = 'Rent contract');

任何人都可以建议如何在没有第二个的情况下做到这一点 select?

使用左连接和过滤器,其中左 table 键为空(但您仍然需要嵌套查询来获取名为 Rent contract 的文档子集):

SELECT c.contragent_name
FROM contragents AS c
LEFT JOIN (
   SELECT contragent_id FROM documents WHERE document_name = 'Rent contract'
) AS d ON c.id = d.contragent_id
WHERE d.id IS NULL;

这有时称为受挫加入。受挫连接与未选择连接的性能比较取决于不同的因素,例如正在使用的数据库系统、记录量,有时查询优化器可能使用的数据库 statistics/trends...

好吧,您可以使用左反连接重新表述您的要求:

SELECT c.contragent_name
FROM contragents c
LEFT JOIN documents d
    ON d.contragent_id = c.contragent_id AND
       d.document_name = 'Rent contract'
WHERE
    d.contragent_id IS NULL;

但是,如果您将上面的解释计划和性能与您的子查询方法进行比较,您可能会发现类似的东西。实际上,您当前的方法可以通过添加以下索引轻松提高性能:

CREATE INDEX idx ON documents (contragent_id, document_name);

此索引应允许快速查找 contragents table 中的任何记录。

左连接是一种替代方法:

SELECT c.contragent_name
FROM contragents AS c
  LEFT JOIN documents d. 
         ON c.contragent_id = d.contragent_id 
        AND document_name = 'Rent contract'
WHERE d.contragent_id IS NULL;

但通常情况下 NOT EXISTS 条件是最有效的方法(如果 性能存在差异 - 这在很大程度上取决于所使用的实际 DBMS)。

SELECT c.contragent_name 
FROM contragents c
WHERE NOT EXISTS (SELECT *
                  FROM documents d
                  WHERE d.document_name = 'Rent contract'
                    AND d.contragent_id = c.contragent_id);