NULL in aggregati, join e DISTINCT
Capire come NULL si comporta diversamente nel raggruppamento, nei join e nell'unicità
NULL in aggregati, join e DISTINCT è una lezione SQL Interview Prep gratuita su CoddyKit. Questa è la lezione 4 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 Interview Prep, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso SQL Interview Prep include 4 lezioni in totale.
NULL in tre contesti sorprendenti
NULL non si comporta allo stesso modo in ogni contesto. L'ultima lezione tratta i tre casi in cui il suo comportamento sorprende maggiormente i candidati: aggregazioni, join e DISTINCT / GROUP BY.
Il punto ricorrente è che le aggregazioni e i filtri trattano NULL come «da ignorare», mentre il raggruppamento e DISTINCT trattano NULL come «un valore uguale agli altri NULL». È proprio questa incoerenza che gli intervistatori verificano.
Se padroneggia questi casi, avrà completato il quadro sulle domande più comuni relative a NULL nei colloqui SQL.
Le aggregazioni ignorano NULL
La regola principale è questa: le funzioni di aggregazione saltano i valori NULL. SUM, AVG, MIN, MAX e COUNT(column) ignorano completamente gli input NULL, invece di considerarli pari a zero.
Per questo AVG può restituire un valore diverso da quello previsto. Divide la somma dei valori non NULL per il numero di valori non NULL, non per il numero totale di righe.
-- bonus values: 100, 200, NULL
SELECT
SUM(bonus) AS total, -- 300 (NULL ignored)
AVG(bonus) AS average, -- 150 = 300 / 2, not / 3
COUNT(bonus) AS cnt -- 2 (NULL not counted)
FROM employees;COUNT(*) e COUNT(column)
È la domanda più frequente sui NULL nelle aggregazioni. COUNT(*) conta le righe, incluse quelle con valori NULL. COUNT(column) conta solo le righe in cui la colonna è non NULL.
La differenza tra i due valori corrisponde esattamente al numero di NULL presenti nella colonna. COUNT(DISTINCT column) fa un passo ulteriore: ignora anch'esso i NULL ed elimina i duplicati.
SELECT
COUNT(*) AS rows_total, -- all rows
COUNT(bonus) AS non_null_bonus, -- excludes NULLs
COUNT(DISTINCT bonus) AS distinct_bonus, -- excludes NULLs + dups
COUNT(*) - COUNT(bonus) AS null_bonus
FROM employees;AVG rispetto a SUM/COUNT(*): un classico trabocchetto
Gli intervistatori chiedono: «AVG(x) equivale a SUM(x) / COUNT(*)?». La risposta è no quando sono presenti valori NULL.
AVG(x) equivale a SUM(x) / COUNT(x) e divide per il numero di valori non NULL. Dividere invece per COUNT(*) tratta i NULL come se fossero zero, abbassando la media.
Se desidera davvero considerare i NULL come zero, deve indicarlo esplicitamente con COALESCE.
-- These differ when bonus has NULLs:
SELECT
AVG(bonus) AS avg_ignoring_nulls,
SUM(bonus) * 1.0 / COUNT(*) AS avg_nulls_as_zero,
AVG(COALESCE(bonus, 0)) AS explicit_nulls_as_zero
FROM employees;Il caso limite dell'aggregazione con tutti valori NULL
Che cosa restituisce un'aggregazione quando ogni input è NULL o non ci sono righe? Ecco una distinzione precisa che gli intervistatori apprezzano:
SUM,AVG,MINeMAXsu righe tutte NULL o su zero righe restituiscono NULL.COUNTrestituisce sempre 0, mai NULL.
Quindi, se un report mostra totali vuoti, una possibile causa è un SUM composto interamente da NULL. Lo racchiuda in COALESCE per visualizzare 0.
-- No matching rows or all bonuses NULL:
SELECT SUM(bonus) FROM employees WHERE 1 = 0; -- NULL
SELECT COUNT(bonus) FROM employees WHERE 1 = 0; -- 0
-- Present a clean zero:
SELECT COALESCE(SUM(bonus), 0) FROM employees;NULL nelle condizioni di JOIN
Nella clausola ON di un join, NULL = NULL restituisce ancora UNKNOWN, quindi le chiavi NULL non corrispondono mai in un equi-join. Due righe che hanno entrambe una chiave di join NULL non verranno abbinate.
Questo è un caso che spesso sorprende quando si lavora con chiavi esterne opzionali. Se il comportamento desiderato è far corrispondere NULL con NULL, serve un operatore NULL-safe (IS NOT DISTINCT FROM o <=>) della lezione precedente.
-- Rows with region IS NULL on both sides do NOT match
SELECT *
FROM a JOIN b ON a.region = b.region;
-- To match NULL-to-NULL (ANSI):
SELECT *
FROM a JOIN b ON a.region IS NOT DISTINCT FROM b.region;I NULL prodotti dagli outer join
Gli outer join generano valori NULL per le righe senza corrispondenza. Dopo un LEFT JOIN, ogni colonna del lato destro è NULL per le righe del lato sinistro che non hanno trovato corrispondenze.
Questa è la base del modello anti-join: utilizzi il filtro WHERE right_table.key IS NULL per trovare le righe senza corrispondenza, ad esempio i clienti senza ordini.
Faccia però attenzione: filtrare in WHERE una colonna proveniente da un outer join può convertirlo accidentalmente di nuovo in un inner join. Questo è l'argomento della scena successiva.
-- Find customers who have never ordered (anti-join)
SELECT c.id, c.name
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.id IS NULL;Il trabocchetto dei NULL con WHERE sugli outer join
È un caso insidioso molto comune. Si esegue un LEFT JOIN su orders e poi si aggiunge WHERE o.status = 'shipped'. Improvvisamente i clienti senza ordini scompaiono, trasformando di fatto l'outer join in un inner join.
Perché? Nelle righe senza corrispondenza o.status è NULL e NULL = 'shipped' restituisce UNKNOWN, quindi WHERE le elimina. Per conservare le righe senza corrispondenza, sposti invece la condizione nella clausola ON.
-- Accidental inner join: drops customers with no orders
SELECT c.name, o.status
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.status = 'shipped';
-- Correct: keep unmatched customers
SELECT c.name, o.status
FROM customers c
LEFT JOIN orders o
ON o.customer_id = c.id AND o.status = 'shipped';DISTINCT tratta tutti i NULL come uguali
Ecco l'incoerenza che sorprende tutti. Le funzioni di aggregazione ignorano NULL, ma DISTINCT mantiene esattamente un NULL, trattando tutti i NULL come duplicati l'uno dell'altro.
Quindi SELECT DISTINCT bonus applicato ai valori 100, 100, NULL, NULL restituisce tre righe: 100, NULL e nient'altro. I due NULL vengono ridotti a uno solo, anche se in altri contesti NULL = NULL restituisce UNKNOWN.
-- bonus: 100, 100, NULL, NULL, 200
SELECT DISTINCT bonus FROM employees;
-- Returns: 100, 200, NULL (the two NULLs become one row)GROUP BY riunisce tutti i NULL in un unico gruppo
GROUP BY segue la stessa regola di DISTINCT: tutte le chiavi NULL vengono raccolte in un unico gruppo. Questo è l'opposto della logica dei confronti, in cui i NULL non sono mai uguali tra loro.
Raggruppando per una colonna nullable si ottiene quindi una riga che rappresenta tutti i record con chiave NULL, che è solitamente ciò che serve nei report. Menzioni questo contrasto (raggruppamento rispetto a confronto) per dimostrare una comprensione approfondita.
-- All employees with NULL department form ONE group
SELECT department, COUNT(*) AS headcount
FROM employees
GROUP BY department;
-- A single row where department is NULL totals all of themPunti chiave per il colloquio
Il riepilogo unificante che impressiona gli intervistatori:
- Le funzioni di aggregazione ignorano NULL; AVG divide per COUNT(column), non per COUNT(*).
- COUNT(*) conta le righe; COUNT(col) e COUNT(DISTINCT col) ignorano NULL.
- SUM/AVG/MIN/MAX su nessuna riga restituiscono NULL; COUNT restituisce 0.
- Nei join, le chiavi NULL non corrispondono mai; filtrare in WHERE una colonna ottenuta da un outer join lo trasforma silenziosamente in un inner join.
- DISTINCT e GROUP BY trattano tutti i NULL come uguali, l'opposto della logica dei confronti.
La frase da ricordare: 'NULL viene ignorato nelle aggregazioni e nei confronti, ma viene raggruppato quando si eliminano i duplicati.'
Verifica rapida
Verifichi il contrasto tra raggruppamento e aggregazione.
Riepilogo
Ha completato la gestione di NULL in vista dei colloqui:
- Le funzioni di aggregazione ignorano NULL; AVG divide per il numero di valori non NULL e, se tutti i valori sono NULL, SUM restituisce NULL mentre COUNT restituisce 0.
COUNT(*)include le righe con NULL;COUNT(col)no, e la differenza corrisponde al numero di NULL.- Le chiavi di join che sono NULL non corrispondono mai; filtrare in WHERE le colonne ottenute da un outer join può ridurre il risultato a un inner join.
- DISTINCT e GROUP BY riuniscono tutti i NULL in un unico gruppo, l'opposto della logica dei confronti.
Ricordi la frase guida: NULL viene ignorato nelle aggregazioni e nei confronti, ma viene raggruppato quando si eliminano i duplicati. Questa singola intuizione risponde alla maggior parte delle domande da colloquio su NULL.
Domande Frequenti
La lezione «NULL in aggregati, join e DISTINCT» è gratuita?
Sì — il testo completo di «NULL in aggregati, join e DISTINCT» è 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 Interview Prep, passa a CoddyKit PRO. Il corso SQL Interview Prep include 4 lezioni in totale.
Cosa imparerò in «NULL in aggregati, join e DISTINCT»?
Capire come NULL si comporta diversamente nel raggruppamento, nei join e nell'unicità Eserciti SQL Interview Prep 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 Interview Prep?
Non è richiesta alcuna esperienza precedente. SQL Interview Prep su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.
Quanto tempo richiede la lezione «NULL in aggregati, join e DISTINCT»?
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 Interview Prep?
Sì. Ogni lezione SQL Interview Prep 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
- Logica a tre valori e UNKNOWN
- IS NULL, IS NOT NULL ed eguaglianza NULL-safe
- COALESCE, NULLIF e ISNULL
- NULL in aggregati, join e DISTINCT