204

I have two tables with binding primary keys in the database and I want to find a disjoint set between them. For example,

Table1

ID Name
1 John
2 Peter
3 Mary

Table2

ID Address
1 address2
2 address2

So how do I create a SQL query so I can fetch the row with ID from table1 that is not in table2? In this case, (3, Mary) should be returned.

PS: The ID is the primary key for those two tables.

3
  • 4
    As a tip for future questions: always define what database system (and which version of that database) you're using. SQL is just the Structured Query Language used by most database systems - that doesn't really help much ... often, databases have extensions and features way beyond the ANSI/ISO SQL Standard that make solving the problem easy - but for that, you need to tell us what database you're using Commented Aug 21, 2012 at 5:33
  • 9
    @marc_s: What if they're looking for a language-agnostic solution, because they need to support multiple underlying database systems, or the database implementation is abstracted away? Commented Jun 2, 2014 at 22:47
  • 1
    Hi @marc_s, I am using PostgreSQL in this case. Thanks for the reminding. Commented Apr 6, 2019 at 1:34

6 Answers 6

306

Try this

SELECT ID, Name 
FROM   Table1 
WHERE  ID NOT IN (SELECT ID FROM Table2)
Sign up to request clarification or add additional context in comments.

8 Comments

@PrinceJea actually it depends. See here for clarification
No Idea why but it's not working. I have around 10000 rows to in table. In my case @JohnWoo 's solution worked just fine.
It's will not work we too many values in "Not In" since this method has a limited number of values cf : dba-oracle.com/t_maximum_number_of_sql_in_list_values.htm
I had to do it like this: select i from Table1 WHERE i NOT IN (SELECT i FROM Table2 where i is not null) and i is not null
This should not be the answer of choice. Well... At least for Postgres, potentially for others RDBMS vendors. Pretty old but still gold: explainextended.com/2009/09/16/…
|
168

Use LEFT JOIN

SELECT  a.*
FROM    table1 a
            LEFT JOIN table2 b
                on a.ID = b.ID
WHERE   b.id IS NULL

3 Comments

I think this is the faster approach for a very large database
I have about 500k rows in my tables and this ran instantly. Before finding this, I naively tried the accepted solution and still hadn't finished running after 10 minutes.
This should be the accepted answer. However it runs slower when Table2 has fewer entries compared to Table1
62

There are basically 3 approaches to that: not exists, not in and left join / is null.

LEFT JOIN with IS NULL

SELECT  l.*
FROM    t_left l
LEFT JOIN
        t_right r
ON      r.value = l.value
WHERE   r.value IS NULL

NOT IN

SELECT  l.*
FROM    t_left l
WHERE   l.value NOT IN
        (
        SELECT  value
        FROM    t_right r
        )

NOT EXISTS

SELECT  l.*
FROM    t_left l
WHERE   NOT EXISTS
        (
        SELECT  NULL
        FROM    t_right r
        WHERE   r.value = l.value
        )

Which one is better? The answer to this question might be better to be broken down to major specific RDBMS vendors. Generally speaking, one should avoid using select ... where ... in (select...) when the magnitude of number of records in the sub-query is unknown. Some vendors might limit the size. Oracle, for example, has a limit of 1,000. Best thing to do is to try all three and show the execution plan.

Specifically form PostgreSQL, execution plan of NOT EXISTS and LEFT JOIN / IS NULL are the same. I personally prefer the NOT EXISTS option because it shows better the intent. After all the semantic is that you want to find records in A that its pk do not exist in B.

Old but still gold, specific to PostgreSQL though: https://explainextended.com/2009/09/16/not-in-vs-not-exists-vs-left-join-is-null-postgresql/

2 Comments

I tied all 3 of these in my Stored Proc. The first suggestion (LEFT JOIN with IS NULL) was by far the fastest.
12

Fast Alternative

I ran some tests (on postgres 9.5) using two tables with ~2M rows each. This query below performed at least 5* better than the other queries proposed:

-- Count
SELECT count(*) FROM (
    (SELECT id FROM table1) EXCEPT (SELECT id FROM table2)
) t1_not_in_t2;

-- Get full row
SELECT table1.* FROM (
    (SELECT id FROM table1) EXCEPT (SELECT id FROM table2)
) t1_not_in_t2 JOIN table1 ON t1_not_in_t2.id=table1.id;

1 Comment

This was not faster than @Jhon Woo's solution. I am using Postgres 9.6 and with Jhon's solution runtime is about 60ms. While I quite this solution after 120 sec and no result.
7

Keeping in mind the points made in @John Woo's comment/link above, this is how I typically would handle it:

SELECT t1.ID, t1.Name 
FROM   Table1 t1
WHERE  NOT EXISTS (
    SELECT TOP 1 NULL
    FROM Table2 t2
    WHERE t1.ID = t2.ID
)

Comments

2
SELECT COUNT(ID) FROM tblA a
WHERE a.ID NOT IN (SELECT b.ID FROM tblB b)    --For count


SELECT ID FROM tblA a
WHERE a.ID NOT IN (SELECT b.ID FROM tblB b)    --For results

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.