Requête SQL pour trouver l'enregistrement dont l'ID n'est pas dans une autre table


123

J'ai deux tables avec la clé primaire de liaison dans la base de données et je souhaite trouver un ensemble disjoint entre elles. Par exemple,

  • Table1contient des colonnes ( ID, Name) et des exemples de données:(1 ,John), (2, Peter), (3, Mary)
  • Table2contient des colonnes ( ID, Address) et des exemples de données:(1, address2), (2, address2)

Alors, comment puis-je créer une requête SQL afin de pouvoir récupérer la ligne avec l'ID table1qui n'est pas dans table2. Dans ce cas, (3, Mary)doit être retourné?

Ps. L'ID est la clé primaire de ces deux tables.

Merci d'avance.


3
Comme astuce pour les questions futures: définissez toujours quel système de base de données (et quelle version de cette base de données) vous utilisez. SQL est juste le langage de requête structuré utilisé par la plupart des systèmes de base de données - cela n'aide pas vraiment beaucoup ... souvent, les bases de données ont des extensions et des fonctionnalités bien au-delà de la norme SQL ANSI / ISO qui facilitent la résolution du problème - mais pour cela, vous besoin de nous dire quelle base de données vous utilisez
marc_s

5
@marc_s: Que se passe-t-il s'ils recherchent une solution indépendante du langage, parce qu'ils doivent prendre en charge plusieurs systèmes de base de données sous-jacents ou si l'implémentation de la base de données est abstraite?
dwanderson le

Salut @marc_s, j'utilise PostgreSQL dans ce cas. Merci pour le rappel.
johnklee

Réponses:


213

Essaye ça

SELECT ID, Name 
FROM   Table1 
WHERE  ID NOT IN (SELECT ID FROM Table2)

8
@PrinceJea en fait cela dépend. Voir ici pour clarification
John Woo

Quand j'ai 20 données, cela fonctionne, mais quand j'ai 20000 données, cela ne fonctionne pas, je suis confus maintenant.
Frank

1
Aucune idée pourquoi mais cela ne fonctionne pas. J'ai environ 10000 lignes dans le tableau. Dans mon cas, la solution de @JohnWoo fonctionnait très bien.
Munam Yousuf

4
Cela ne fonctionnera pas nous avons trop de valeurs dans "Not In" puisque cette méthode a un nombre limité de valeurs cf: dba-oracle.com/t_maximum_number_of_sql_in_list_values.htm
G.Busato

2
Je devais le faire comme ceci: sélectionnez i dans Table1 WHERE i NOT IN (SELECT i FROM Table2 où i n'est pas nul ) et i n'est pas nul
jaksco

93

Utilisation LEFT JOIN

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

Je pense que c'est l'approche la plus rapide pour une très grande base de données
Alex Jolig

12

Il existe essentiellement 3 approches: que not exists, not inet left join / is null.

JOINT GAUCHE avec IS NULL

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

PAS DEDANS

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

N'EXISTE PAS

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

Quel est le meilleur? La réponse à cette question pourrait être mieux répartie entre les principaux fournisseurs de SGBDR spécifiques. D'une manière générale, il faut éviter d'utiliser select ... where ... in (select...)lorsque l'ampleur du nombre d'enregistrements dans la sous-requête est inconnue. Certains fournisseurs peuvent limiter la taille. Oracle, par exemple, a une limite de 1 000 . La meilleure chose à faire est d'essayer les trois et de montrer le plan d'exécution.

Formulaire spécifiquement PostgreSQL, plan d'exécution NOT EXISTSet LEFT JOIN / IS NULLsont les mêmes. Personnellement, je préfère l' NOT EXISTSoption car elle montre mieux l'intention. Après tout la sémantique est que vous voulez trouver les enregistrements dans A que ses pk n'existent pas dans B .

Vieux mais toujours doré, spécifique à PostgreSQL cependant: https://explainextended.com/2009/09/16/not-in-vs-not-exists-vs-left-join-is-null-postgresql/


10

Alternative rapide

J'ai effectué quelques tests (sur postgres 9.5) en utilisant deux tables avec ~ 2M lignes chacune. Cette requête ci-dessous a effectué au moins 5 * mieux que les autres requêtes proposées:

-- 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
Ce n'était pas plus rapide que la solution de @Jhon Woo. J'utilise Postgres 9.6 et avec la solution de Jhon, la durée d'exécution est d'environ 60 ms. Alors que j'ai assez cette solution après 120 secondes et aucun résultat.
froy001

5

En gardant à l'esprit les points soulevés dans le commentaire / lien de @John Woo ci-dessus, voici comment je le gérerais généralement:

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

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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.