Come selezionare tutti i record da una tabella che non esistono in un'altra tabella?


470

tabella1 (ID, nome)
tabella2 (ID, nome)

Query:

SELECT name   
FROM table2  
-- that are not in table1 already

Risposte:


844
SELECT t1.name
FROM table1 t1
LEFT JOIN table2 t2 ON t2.name = t1.name
WHERE t2.name IS NULL

D : Cosa sta succedendo qui?

A : Concettualmente, selezioniamo tutte le righe da table1e per ogni riga proviamo a trovare una riga table2con lo stesso valore per la namecolonna. Se non esiste tale riga, lasciamo table2vuota solo la parte del nostro risultato per quella riga. Quindi limitiamo la nostra selezione selezionando solo quelle righe nel risultato in cui la riga corrispondente non esiste. Infine, ignoriamo tutti i campi dal nostro risultato tranne la namecolonna (quella di cui siamo sicuri che esiste, da table1).

Anche se potrebbe non essere il metodo più performante possibile in tutti i casi, dovrebbe funzionare praticamente in tutti i motori di database che tentano di implementare ANSI 92 SQL


16
@ z-boss: è anche il meno performante su SQL Server: spieginextended.com/2009/09/15/…
OMG Ponies

7
@BunkerBoy: un join a sinistra consente di non esistere righe a destra senza che ciò influisca sull'inclusione delle righe a sinistra. Un join interno richiede che siano presenti righe a sinistra e a destra. Quello che sto facendo qui è applicare una logica per ottenere sostanzialmente la selezione inversa di un join interno.
Kris

2
omg questo ha aiutato a visualizzare molto facilmente, altri l'avevano detto in 5 modi diversi, ma questo ha aiutato. semplice: prima ottieni l'unione a sinistra, tutto in A e tutto in B che corrisponde ad A. Ma come accade nei campi di unione a sinistra che non si uniscono sono solo nulli. Allora dici, ok, voglio solo che siano nulli. In questo modo ora hai tutte le file in A che non hanno avuto una corrispondenza In B
Muhammad Umer

7
Va notato che questa soluzione (accettata e votata) è l'unica, penso, che potrebbe essere modificata per uno scenario in cui più campi entrano in gioco. In particolare, sto ritornando campo, campo 2, campo 3 dalla tabella uno in cui la combinazione di campo annuncio campo2 non è nella seconda tabella. Oltre a modificare il join in questa risposta, non vedo un modo per farlo con alcune delle altre "risposte più efficienti" di cui si discute di seguito
TMWP

1
Assicurati solo di usare "DOVE t2.name È NULL" e non "AND t2.name IS NULL" perché "e" non daranno risultati corretti. Non capisco davvero perché, ma è un dato di fatto, l'ho provato.
user890332

236

Puoi farlo entrambi

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT name 
     FROM table1)

o

SELECT name 
FROM table2 
WHERE NOT EXISTS 
    (SELECT * 
     FROM table1 
     WHERE table1.name = table2.name)

Vedi questa domanda per 3 tecniche per raggiungere questo obiettivo


38
Questo è incredibilmente lento con grandi quantità di dati.
Lightbulb1

Sì, in effetti è molto lento
virus

Non dovrebbe essere "from table1" nella sottoquery della query inesistente.
Hound,

Molto confuso da come questo ha ottenuto così tanti voti. Trovo molto difficile pensare a un motivo per usarlo mai, quando esiste un approccio a questo problema che è incredibilmente più veloce con circa lo stesso numero di sequenze di tasti.
searchengine27,

Questo ha funzionato per me .. Grazie
Thameem,

81

Non ho abbastanza punti rep per votare la seconda risposta. Ma non sono d'accordo con i commenti sulla risposta in alto. La seconda risposta:

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT name 
     FROM table1)

È molto più efficiente in pratica. Non so perché, ma sto eseguendo contro 800k + record e la differenza è enorme con il vantaggio dato alla seconda risposta postata sopra. Solo i miei $ 0,02


31
Nella query NOT IN la query secondaria viene eseguita una sola volta, nella query EXISTS la query secondaria viene eseguita per ogni riga
Carrick,

2
sei fantastico :) in questo modo converto la mia query di 25 secondi usando il join sinistro in soli 0,1 secondi
Bassem Shahin

3
le risposte non sono in alcun ordine specifico, quindi la seconda risposta non significa ciò che pensavi significasse.

38

Questa è pura teoria dell'insieme che puoi ottenere con l' minusoperazione.

select id, name from table1
minus
select id, name from table2

Pensi che questo sia molto efficace rispetto al join sinistro?
UHS

Dovrebbe essere. Il comando meno è progettato per questa situazione esatta. Naturalmente l'unico modo per giudicare un determinato set di dati è provarlo in entrambi i modi e vedere quale funziona più velocemente.
Inverno

9
In T-SQL, l'operatore set è "tranne". Questo è molto conveniente per me e non ha causato alcun rallentamento.

2
In SQLite, l'operatore "meno" è anche "tranne".
lifjoy,

MySQL non supporta l'operatore MINUS.
Muhammad Azeem,


16

Fai attenzione alle insidie. Se il campo Namein Table1nulli siete sorprese. Meglio è:

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT ISNULL(name ,'')
     FROM table1)

1
COALESCE> ISNULL (ISNULL è un'inutile aggiunta T-SQL al linguaggio che non fa nulla di nuovo o migliore di COALESCE)
Kris

14

Ecco cosa ha funzionato meglio per me.

SELECT *
FROM @T1
EXCEPT
SELECT a.*
FROM @T1 a
JOIN @T2 b ON a.ID = b.ID

Questo è stato più del doppio rispetto a qualsiasi altro metodo che ho provato.


Grazie, funziona bene anche con grandi quantità di dati! Ma mi sto solo chiedendo il termine "Tranne".
PatsonLeaner,


7

Quel lavoro ha funzionato bene per me

SELECT * 
FROM [dbo].[table1] t1
LEFT JOIN [dbo].[table2] t2 ON t1.[t1_ID] = t2.[t2_ID]
WHERE t2.[t2_ID] IS NULL

1

Vedi query:

SELECT * FROM Table1 WHERE
id NOT IN (SELECT 
        e.id
    FROM
        Table1 e
            INNER JOIN
        Table2 s ON e.id = s.id);

Concettualmente sarebbe: recuperare i record corrispondenti nella sottoquery e quindi nella query principale recuperare i record che non sono nella sottoquery.


0

Ripubblicherò (dato che non sono ancora abbastanza forte da commentare) nella risposta corretta ... nel caso in cui qualcun altro pensasse che fosse necessario spiegarlo meglio.

SELECT temp_table_1.name
FROM original_table_1 temp_table_1
LEFT JOIN original_table_2 temp_table_2 ON temp_table_2.name = temp_table_1.name
WHERE temp_table_2.name IS NULL

E ho visto la sintassi in FROM che ha bisogno di virgole tra i nomi delle tabelle in mySQL ma in sqlLite sembrava preferire lo spazio.

La linea di fondo è quando si usano nomi di variabili errate che lasciano domande. Le mie variabili dovrebbero avere più senso. E qualcuno dovrebbe spiegare perché abbiamo bisogno di una virgola o nessuna virgola.


0

Se si desidera selezionare un utente specifico

SELECT tent_nmr FROM Statio_Tentative_Mstr
WHERE tent_npk = '90009'
AND
tent_nmr NOT IN (SELECT permintaan_tent FROM Statio_Permintaan_Mstr)

La tent_npkè una chiave primaria di un utente

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.