web-dev-qa-db-fra.com

Requête SQL pour trouver l'enregistrement avec l'ID pas dans une autre table

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

  • Table1 a des colonnes (ID, Name) et des exemples de données: (1 ,John), (2, Peter), (3, Mary)
  • Table2 a 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 que je puisse récupérer la ligne avec l'ID de table1 qui n'est pas dans table2. Dans ce cas, (3, Mary) devrait être retourné?

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

Merci d'avance.

102
johnklee

Essaye ça

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

Utilisez LEFT JOIN

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

Alternative rapide

J'ai exécuté des tests (sur Postgres 9.5) en utilisant deux tables avec environ 2 millions de lignes chacune. Cette requête ci-dessous a eu au moins 5 * de meilleurs résultats 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;
9
polvoazul

Gardant à l'esprit les remarques faites 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
)
5
CaseyR

Il existe essentiellement 3 approches pour cela: not exists, not in et left join / is null.

JOINDRE 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? Il serait peut-être préférable de répondre à cette question en fonction des principaux fournisseurs de SGBDR spécifiques. En règle générale, évitez d'utiliser select ... where ... in (select...) lorsque l'ampleur du nombre d'enregistrements de la sous-requête est inconnue. Certains vendeurs peuvent limiter la taille. Oracle, par exemple, a un limite de 1 0 . La meilleure chose à faire est d'essayer les trois et de montrer le plan d'exécution.

En particulier dans PostgreSQL, le plan d’exécution de NOT EXISTS et LEFT JOIN / IS NULL est identique. Personnellement, je préfère l’option NOT EXISTS car elle montre mieux l’intention. Après toute la sémantique, c’est que vous voulez trouver des enregistrements dans A et que ses pk n’existent pas dans B .

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

4
L. Holanda
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
2
JoshYates1980