Come trovo i record che non sono stati uniti?
Domanda
Ho due tabelle che sono unite insieme.
A ha molti B
Normalmente faresti:
select * from a,b where b.a_id = a.id
Per ottenere tutti i record da un che ha un record in b.
Come posso ottenere solo i record in a che non hanno nulla in b?
Soluzione
select * from a where id not in (select a_id from b)
O come altre persone su questo thread dicono:
select a.* from a
left outer join b on a.id = b.a_id
where b.a_id is null
Altri suggerimenti
select * from a
left outer join b on a.id = b.a_id
where b.a_id is null
Un altro approccio:
select * from a where not exists (select * from b where b.a_id = a.id)
Il " esiste " l'approccio è utile se esiste qualche altro "dove" clausola che devi allegare alla query interna.
SELECT id FROM a
EXCEPT
SELECT a_id FROM b;
seleziona * da un ID in cui non si trova (seleziona a_id da b)
Probabilmente otterrai prestazioni molto migliori (rispetto all'uso di 'non in') se usi un join esterno:
select * from a left outer join b on a.id = b.a_id where b.a_id is null;
Questo ti proteggerà da null nella clausola IN, che può causare comportamenti imprevisti.
seleziona * da un ID dove non è presente (seleziona [un ID] da b dove [un ID] non è nullo )
Nel caso di un join è piuttosto veloce, ma quando stiamo rimuovendo i record dal database che ha circa 50 milioni di record e 4 e più join a causa di chiavi esterne, ci vogliono alcuni minuti per farlo. Molto più veloce da usare in condizioni WHERE NOT IN come questa:
select a.* from a
where a.id NOT IN(SELECT DISTINCT a_id FROM b where a_id IS NOT NULL)
//And for more joins
AND a.id NOT IN(SELECT DISTINCT a_id FROM c where a_id IS NOT NULL)
Posso anche raccomandare questo approccio per l'eliminazione nel caso in cui non abbiamo configurato l'eliminazione in cascata. Questa query richiede solo pochi secondi.
Il primo approccio è
select a.* from a where a.id not in (select b.ida from b)
il secondo approccio è
select a.*
from a left outer join b on a.id = b.ida
where b.ida is null
Il primo approccio è molto costoso. Il secondo approccio è migliore.
Con PostgreSql 9.4 ho fatto la "spiegazione della query" funzione e la prima query come costo di costo = 0,00..1982043603.32 . Invece la query di join ha un costo di cost=45946.77..45946.78
Ad esempio, cerco tutti i prodotti che non sono compatibili senza veicoli. Ho 100.000 prodotti e oltre 1 milione di compatibilità.
select count(*) from product a left outer join compatible c on a.id=c.idprod where c.idprod is null
La query di join ha impiegato circa 5 secondi, invece la versione della sottoquery non è mai terminata dopo 3 minuti.
Un altro modo di scriverlo
select a.*
from a
left outer join b
on a.id = b.id
where b.id is null
Ouch, battuto da Nathan :)