Vai al contenuto
eLearner.app
Modulo 5 · Lezione 4 di 420/57 nel corso~12 min
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.

SQL
-- 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:

SQL
SELECT email FROM customers WHERE country = 'Italia'
UNION
SELECT email FROM customers WHERE country = 'Francia';

Regole:

  • le due SELECT devono avere lo stesso numero di colonne, con tipi compatibili;
  • UNION (senza ALL) elimina i duplicati — fa di fatto un DISTINCT sul risultato finale;
  • UNION ALL mantiene anche i duplicati, ed è molto più veloce perché evita il sort/hash per la deduplicazione.
SQL
-- 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").

SQL
-- 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

Esercizio#sql.m5.l4.e1
Tentativi: 0Caricamento…

Trova tutte le email dei clienti che hanno ordinato qualcosa OPPURE recensito qualcosa (senza duplicati). Una colonna: email. Ordina per email.

Caricamento editor…
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

Esercizio#sql.m5.l4.e2
Tentativi: 0Caricamento…

Trova le email dei clienti che hanno ordinato ma non hanno mai recensito nulla. Usa EXCEPT. Una colonna: email. Ordina per email.

Caricamento editor…
Mostra suggerimento

EXCEPT mantiene solo le righe della SELECT di sinistra non presenti in quella di destra.

Soluzione disponibile dopo 3 tentativi