Lezioni del modulo (4/4)
UNION, INTERSECT, EXCEPT (e CROSS JOIN)
Finora hai combinato dati orizzontalmente: JOIN accosta colonne di
righe correlate. SQL offre però anche un'altra famiglia di operatori che
combina dati verticalmente, trattando i risultati di due SELECT come
insiemi: UNION, INTERSECT, EXCEPT. In più rivediamo CROSS JOIN,
il prodotto cartesiano.
CROSS JOIN: ogni riga con ogni riga
CROSS JOIN non ha una ON: produce ogni combinazione possibile di
righe fra due tabelle (prodotto cartesiano). Se A ha n righe e B ha
m righe, il risultato ne ha n × m.
-- Tutte le combinazioni cliente × prodotto:
SELECT c.email, p.name
FROM customers c
CROSS JOIN products p;12 clienti × 16 prodotti = 192 righe. Si usa raramente sui dati reali (è costoso!), ma è utile per:
- generare combinazioni "tutte contro tutte" (es. matrice di compatibilità);
- accoppiare una tabella con una piccola tabella di costanti / parametri.
UNION e UNION ALL
UNION mette in coda i risultati di due SELECT con lo stesso numero e
tipo di colonne:
SELECT email FROM customers WHERE country = 'Italia'
UNION
SELECT email FROM customers WHERE country = 'Francia';Regole:
- le due
SELECTdevono avere lo stesso numero di colonne, con tipi compatibili; UNION(senzaALL) elimina i duplicati — fa di fatto unDISTINCTsul risultato finale;UNION ALLmantiene anche i duplicati, ed è molto più veloce perché evita il sort/hash per la deduplicazione.
-- Email di clienti che hanno ordinato O recensito qualcosa, senza duplicati:
SELECT c.email
FROM customers c JOIN orders o ON o.customer_id = c.id
UNION
SELECT c.email
FROM customers c JOIN reviews r ON r.customer_id = c.id;INTERSECT ed EXCEPT
INTERSECT tiene solo le righe presenti in entrambi i risultati;
EXCEPT tiene le righe del primo non presenti nel secondo (la
"differenza insiemistica").
-- Clienti che hanno sia ordinato sia recensito:
SELECT c.email FROM customers c JOIN orders o ON o.customer_id = c.id
INTERSECT
SELECT c.email FROM customers c JOIN reviews r ON r.customer_id = c.id;
-- Clienti che hanno ordinato ma mai recensito:
SELECT c.email FROM customers c JOIN orders o ON o.customer_id = c.id
EXCEPT
SELECT c.email FROM customers c JOIN reviews r ON r.customer_id = c.id;Anche INTERSECT ed EXCEPT eliminano i duplicati di default; le varianti
INTERSECT ALL / EXCEPT ALL non lo fanno.
Prova tu
Trova tutte le email dei clienti che hanno ordinato qualcosa OPPURE recensito qualcosa (senza duplicati). Una colonna: email. Ordina per email.
Mostra suggerimento
UNION fra due SELECT che restituiscono la stessa colonna email. L'ORDER BY va alla fine, sul risultato finale.
Soluzione disponibile dopo 3 tentativi
Esercizio di ripasso
Trova le email dei clienti che hanno ordinato ma non hanno mai recensito nulla. Usa EXCEPT. Una colonna: email. Ordina per email.
Mostra suggerimento
EXCEPT mantiene solo le righe della SELECT di sinistra non presenti in quella di destra.
Soluzione disponibile dopo 3 tentativi