Anti-join e semi-join (NOT EXISTS)
Trovi le «righe in A senza corrispondenza in B» con un anti-join e le «righe in A con almeno una corrispondenza in B» con un semi-join, usando EXISTS/NOT EXISTS
Anti-join e semi-join (NOT EXISTS) è una lezione SQL Academy gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento SQL Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso SQL Academy include 4 lezioni in totale.
Semi-join: "ha almeno una corrispondenza"
Restituisce le righe di A che hanno almeno una riga corrispondente in B, ma solo le colonne di A. SQL implementa i semi-join tramite EXISTS o IN.
Semi-join con EXISTS
Utenti che hanno effettuato almeno un ordine:
SELECT u.* FROM users u
WHERE EXISTS (
SELECT 1 FROM orders o WHERE o.user_id = u.id
);Semi-join con IN
Stesso risultato, stile diverso:
SELECT * FROM users
WHERE id IN (SELECT user_id FROM orders);Perché EXISTS spesso è più efficiente
EXISTS interrompe la ricerca al primo risultato: si ferma alla prima corrispondenza per ogni riga esterna. IN può materializzare l'intero insieme interno. I pianificatori moderni spesso ottimizzano le due forme nello stesso piano, ma EXISTS è la scelta più sicura per insiemi interni molto grandi.
Anti-join: "non ha corrispondenze"
Utenti che non hanno MAI effettuato un ordine: esistono tre forme idiomatiche:
-- NOT EXISTS (preferred):
SELECT u.* FROM users u
WHERE NOT EXISTS (
SELECT 1 FROM orders o WHERE o.user_id = u.id
);
-- LEFT JOIN ... IS NULL:
SELECT u.* FROM users u
LEFT JOIN orders o ON o.user_id = u.id
WHERE o.id IS NULL;
-- NOT IN (risky with NULLs):
SELECT * FROM users WHERE id NOT IN (SELECT user_id FROM orders);Perché NOT IN è rischioso
Se la sottoquery interna contiene NULL, NOT IN restituisce NULL e WHERE scarta le righe per cui il predicato è NULL. Risultato: nessuna riga. NOT EXISTS non presenta questo problema.
Ottimizzazione del pianificatore
PostgreSQL moderno riconosce EXISTS e NOT EXISTS come schemi di semi-join e anti-join e può eseguirli con hash join:
EXPLAIN ANALYZE
SELECT u.* FROM users u
WHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id);
-- → Hash Anti JoinAnti-join su più colonne
Usi chiavi composte:
SELECT * FROM order_items oi
WHERE NOT EXISTS (
SELECT 1 FROM shipments s
WHERE s.order_id = oi.order_id
AND s.line_no = oi.line_no
);Semi-join con EXISTS + predicato aggiuntivo
Aggiunga filtri alla sottoquery interna:
SELECT u.* FROM users u
WHERE EXISTS (
SELECT 1 FROM orders o
WHERE o.user_id = u.id
AND o.status = 'paid'
AND o.created_at >= NOW() - INTERVAL '30 days'
);Indicizzare la colonna di correlazione
Sia EXISTS sia NOT EXISTS filtrano la sottoquery interna in base alla chiave della riga esterna. Senza un indice su quella chiave, viene eseguita una scansione per ogni riga esterna:
CREATE INDEX orders_user_id_idx ON orders(user_id);Quando usare LEFT JOIN ... IS NULL
Per dashboard che richiedono anche le colonne del lato senza corrispondenze, lo stile LEFT JOIN è naturale. Per la semantica di un puro anti-join, NOT EXISTS è più chiaro.
Oltre SQL: i filtri Bloom
Per anti-join molto grandi, un pre-filtro basato su un filtro Bloom può essere utile. PostgreSQL supporta gli indici bloom tramite l'estensione bloom.
Riepilogo
Semi-join = "ha una corrispondenza"; anti-join = "non ha corrispondenze".
- EXISTS per i semi-join
- NOT EXISTS per gli anti-join (sicuro rispetto a NULL)
- Indicizzi la colonna di correlazione
- Eviti NOT IN a meno che l'insieme interno non possa contenere NULL
Verifica rapida
Desidera trovare gli utenti che non hanno MAI effettuato un ordine. Qual è la soluzione SQL più sicura e idiomatica?
Domande Frequenti
La lezione «Anti-join e semi-join (NOT EXISTS)» è gratuita?
Sì — il testo completo di «Anti-join e semi-join (NOT EXISTS)» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso SQL Academy, passa a CoddyKit PRO. Il corso SQL Academy include 4 lezioni in totale.
Cosa imparerò in «Anti-join e semi-join (NOT EXISTS)»?
Trovi le «righe in A senza corrispondenza in B» con un anti-join e le «righe in A con almeno una corrispondenza in B» con un semi-join, usando EXISTS/NOT EXISTS Eserciti SQL Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare SQL Academy?
Non è richiesta alcuna esperienza precedente. SQL Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.
Quanto tempo richiede la lezione «Anti-join e semi-join (NOT EXISTS)»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione SQL Academy?
Sì. Ogni lezione SQL Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Cross join e prodotti cartesiani
- Join laterali (LATERAL JOIN)
- Anti-join e semi-join (NOT EXISTS)
- Ottimizzazione delle prestazioni delle join tra più tabelle