Query SQL per trovare record con ID non in un'altra tabella


123

Ho due tabelle con chiave primaria vincolante nel database e desidero trovare un insieme disgiunto tra di loro. Per esempio,

  • Table1ha colonne ( ID, Name) e dati di esempio:(1 ,John), (2, Peter), (3, Mary)
  • Table2ha colonne ( ID, Address) e dati di esempio:(1, address2), (2, address2)

Quindi, come creo una query SQL in modo da poter recuperare la riga con ID da table1quella non presente table2. In questo caso, (3, Mary)deve essere restituito?

Ps. L'ID è la chiave primaria per queste due tabelle.

Grazie in anticipo.


3
Come suggerimento per domande future: definisci sempre quale sistema di database (e quale versione di quel database) stai utilizzando. SQL è solo il linguaggio di query strutturato utilizzato dalla maggior parte dei sistemi di database - che non aiuta molto ... spesso, i database hanno estensioni e funzionalità ben oltre lo standard SQL ANSI / ISO che semplifica la risoluzione del problema - ma per questo, tu devi dirci quale database stai utilizzando
marc_s

5
@marc_s: E se stessero cercando una soluzione indipendente dalla lingua, perché hanno bisogno di supportare più sistemi di database sottostanti o l'implementazione del database viene astratta?
dwanderson

Ciao @marc_s, in questo caso sto usando PostgreSQL. Grazie per il ricordo.
johnklee

Risposte:


213

Prova questo

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

8
@PrinceJea in realtà dipende. Vedi qui per chiarimenti
John Woo

Quando ho 20 dati, funziona, ma quando ho 20000 dati, non funziona, ora sono confuso.
Frank

1
Nessuna idea del perché ma non funziona. Ho circa 10000 righe nella tabella. Nel mio caso la soluzione di @JohnWoo ha funzionato bene.
Munam Yousuf

4
Non funzionerà con troppi valori in "Not In" poiché questo metodo ha un numero limitato di valori cf: dba-oracle.com/t_mamost_number_of_sql_in_list_values.htm
G.Busato

2
Ho dovuto farlo in questo modo: seleziona i da Table1 WHERE i NOT IN (SELECT i FROM Table2 dove i non è nullo ) e i non è nullo
jaksco

93

Uso LEFT JOIN

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

Penso che questo sia l'approccio più veloce per un database molto grande
Alex Jolig il

12

Ci sono fondamentalmente 3 approcci che: not exists, not ine 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

NON IN

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

NON ESISTE

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

Qual è il migliore? La risposta a questa domanda potrebbe essere meglio se suddivisa tra i principali fornitori di RDBMS specifici. In generale, si dovrebbe evitare di utilizzare select ... where ... in (select...)quando l'entità del numero di record nella sottoquery è sconosciuta. Alcuni fornitori potrebbero limitare le dimensioni. Oracle, ad esempio, ha un limite di 1.000 . La cosa migliore da fare è provare tutti e tre e mostrare il piano di esecuzione.

In particolare, forma PostgreSQL, piano di esecuzione di NOT EXISTS e LEFT JOIN / IS NULLsono gli stessi. Personalmente preferisco l' NOT EXISTSopzione perché mostra meglio l'intento. Dopo tutto la semantica è che si desidera trovare record in un pk che i suoi non esistono in B .

Vecchio ma ancora d'oro, specifico per PostgreSQL però: https://explainextended.com/2009/09/16/not-in-vs-not-exists-vs-left-join-is-null-postgresql/


10

Alternativa veloce

Ho eseguito alcuni test (su postgres 9.5) utilizzando due tabelle con ~ 2 milioni di righe ciascuna. Questa query di seguito ha eseguito almeno 5 * meglio delle altre query proposte:

-- 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
Non è stato più veloce della soluzione di @Jhon Woo. Sto usando Postgres 9.6 e con la soluzione di Jhon il runtime è di circa 60 ms. Mentre ho abbastanza questa soluzione dopo 120 secondi e nessun risultato.
froy001

5

Tenendo presente i punti fatti nel commento / collegamento di @John Woo sopra, questo è il modo in cui lo gestirò in genere:

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.