VlLight
VlLight

Reputation: 53

How to use JOIN instead of SELECT NOT IN?

I have 2 tables:

I wish to find all customers, for example, that do not have a rent contract.

I can do it such way:

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

Can anybody suggest how to do it without the second select?

Upvotes: 2

Views: 1155

Answers (3)

user330315
user330315

Reputation:

A left join is an alternative:

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;

But typically a NOT EXISTS condition is the most efficient way to do it (if there is a difference in performance - this largely depends on the actual DBMS being used).

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);

Upvotes: 4

Tim Biegeleisen
Tim Biegeleisen

Reputation: 521178

Well you could rephrase your requirement using a left anti-join:

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;

However, if you were to compare the explain plan and performance of the above to your subquery approach, you might find similar things. Actually, your current approach can easily be made performant by adding the following index:

CREATE INDEX idx ON documents (contragent_id, document_name);

This index should allow the rapid lookup of any record in the contragents table.

Upvotes: 4

jleach
jleach

Reputation: 7792

Use a left join and filter where the left table key is null (but you'll still need nested query to get the subset of documents with the name 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;

This is sometimes referred to as a Frustrated Join. Performance comparison for a frustrated join vs a not in selection depends upon varying factors, such as the database system in use, volume of records, sometimes database statistics/trends that a query optimizer may use...

Upvotes: 2

Related Questions