0Pricing
Coding Interview Prep · Lezione

Espansione dei join e moltiplicazione delle righe

Capire perché un join può restituire più righe di entrambe le tabelle e come questo viene verificato ai colloqui

Espansione dei join e moltiplicazione delle righe è una lezione Coding Interview Prep 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 Coding Interview Prep, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Coding Interview Prep include 4 lezioni in totale.

Quando un join restituisce troppe righe

Una delle domande di colloquio più rivelatrici sembra innocua: «un join può restituire più righe della tabella più grande?» La risposta è sì, e il fenomeno si chiama fan-out o moltiplicazione delle righe.

Chi risponde «un join combina semplicemente le tabelle» non coglie il problema. Chi sa prevedere il numero esatto di righe viene assunto. Questa lezione sviluppa proprio questa capacità di previsione.

La causa: corrispondenze uno-a-molti

Il fan-out si verifica quando una riga a sinistra corrisponde a molte righe a destra. Ogni corrispondenza produce una riga di output distinta.

Con clienti e ordini, Ada (un cliente) ha due ordini. Il join produce una riga per ogni ordine, quindi Ada viene duplicata. I campi del cliente si ripetono; cambiano solo quelli dell'ordine.

SELECT c.name, o.amount
FROM customers c
JOIN orders o ON o.customer_id = c.id;
-- Ada appears twice (she has 2 orders)
-- name | amount
-- Ada  | 50
-- Ada  | 20
-- Bob  | 99

Conteggio delle righe di output

Il numero di righe di output è uguale alla somma delle corrispondenze per ogni riga a sinistra, non al numero di clienti.

  • Ada -> 2 ordini -> 2 righe
  • Bob -> 1 ordine -> 1 riga
  • Cleo -> 0 ordini -> 0 righe (eliminata da INNER JOIN)

Totale = 3 righe, anche se customers contiene anch'essa 3 righe. Se Ada passa ad avere 10 ordini, il risultato sale a 11 righe.

Il molti-a-molti fa esplodere il risultato

Il fan-out si amplifica quando entrambi i lati hanno più corrispondenze per la stessa chiave. Se la chiave K compare 3 volte a sinistra e 4 volte a destra, il join produce 3 x 4 = 12 righe per quella chiave.

È così che un join apparentemente piccolo può arrivare a milioni di righe. Gli intervistatori amano fornire chiavi duplicate su entrambi i lati per verificare se individua la moltiplicazione.

-- left has 3 rows with tag 'A', right has 4 rows with tag 'A'
SELECT l.id, r.id
FROM left_t l
JOIN right_t r ON r.tag = l.tag;
-- tag 'A' alone yields 3 * 4 = 12 output rows

La trappola dell'aggregazione

Ecco il bug che gli intervistatori inseriscono più spesso. Unisce orders a order_items per ottenere i dettagli degli articoli, poi somma l'importo dell'ordine. Poiché ogni ordine si moltiplica in più righe degli articoli, l'importo dell'ordine viene conteggiato una volta per ogni articolo.

La SUM risulta ora enormemente gonfiata. La query sembra corretta e viene persino eseguita senza errori, ed è proprio questo a renderla pericolosa.

-- BUG: order.amount duplicated across items
SELECT SUM(o.amount) AS total
FROM orders o
JOIN order_items i ON i.order_id = o.id;
-- a 3-item order counts o.amount 3 times

Come si manifesta il gonfiamento

Supponga che un ordine abbia importo 100 e tre righe di dettaglio. Il join produce tre righe, ognuna con importo 100. SUM(o.amount) restituisce 300, non 100.

La soluzione consiste nell'aggregare alla granularità corretta: sommare gli articoli oppure sommare separatamente gli ordini distinti. Non applichi mai SUM a un valore del padre attraverso un join con fan-out sui figli.

o.id | o.amount | i.id
7    | 100      | 71
7    | 100      | 72
7    | 100      | 73
-- SUM(o.amount) = 300  (WRONG, should be 100)

Soluzione 1: aggregare prima i figli

La soluzione più pulita consiste nel pre-aggregare il lato molti in una sottoquery o in una CTE, in modo che ogni padre corrisponda esattamente a una riga riepilogativa. Niente fan-out e niente gonfiamento.

Qui si riducono gli articoli a una riga per ordine prima del join, così l'importo del padre non viene mai duplicato.

SELECT o.id, o.amount, i.item_count
FROM orders o
JOIN (
  SELECT order_id, COUNT(*) AS item_count
  FROM order_items
  GROUP BY order_id
) i ON i.order_id = o.id;

Soluzione 2: COUNT(DISTINCT) e somme condizionali

Se deve aggregare dopo un join con fan-out, conteggi o sommi alla granularità corretta. Usi COUNT(DISTINCT o.id) per contare gli ordini anziché le righe degli articoli.

Nota: SUM(DISTINCT o.amount) NON è una soluzione sicura, perché due ordini diversi possono legittimamente avere lo stesso importo e verrebbero uniti nel conteggio. Il pre-aggregamento è più affidabile.

SELECT COUNT(DISTINCT o.id)   AS num_orders,
       COUNT(i.id)            AS num_items
FROM orders o
JOIN order_items i ON i.order_id = o.id;

Individuare il fan-out prima che causi problemi

Una verifica rapida apprezzata dagli intervistatori consiste nel controllare se la chiave di join è univoca sul lato che si prevede essere quello «uno». Se il numero di chiavi distinte è inferiore al numero di righe, quel lato contiene duplicati e causerà fan-out.

-- if this returns rows, order_id is NOT unique in order_items
SELECT order_id, COUNT(*) AS n
FROM order_items
GROUP BY order_id
HAVING COUNT(*) > 1;

Verificare la granularità con un conteggio

Prima di fidarsi di un aggregato su un risultato con join, verifichi il numero di righe. Un metodo rapido consiste nel confrontare il conteggio del join con il conteggio della tabella che si prevede definisca la granularità.

Se COUNT(*) sul join è maggiore di COUNT(*) di orders, il join ha prodotto fan-out e qualsiasi aggregato per ordine è a rischio. Questa verifica di una sola riga ha salvato molte risposte ai colloqui.

-- joined rows should equal order count if no fan-out
SELECT COUNT(*) AS joined_rows
FROM orders o
JOIN order_items i ON i.order_id = o.id;

SELECT COUNT(*) AS order_rows FROM orders;
-- joined_rows > order_rows  =>  fan-out present

Il fan-out non è sempre un bug

A volte si desidera ottenere una riga per ogni figlio. Elencare ogni riga di dettaglio insieme all'intestazione dell'ordine è un fan-out corretto. La competenza consiste nel conoscere la propria granularità: quante righe dovrebbe produrre una singola entità?

Dichiari la granularità prima di scrivere la query. «Voglio una riga per ogni articolo dell'ordine» invece di «una riga per ogni ordine» determina se il fan-out è una funzionalità o un bug.

Verifica rapida

Preveda il risultato di un join uno-a-molti.

Riepilogo: fan-out e moltiplicazione delle righe

Da ricordare:

  • Un join produce una riga per ogni coppia corrispondente, quindi le corrispondenze uno-a-molti duplicano il lato «uno».
  • Le chiavi molti-a-molti si moltiplicano: 3 x 4 = 12 righe per quella chiave.
  • Aggregare un valore del padre attraverso un join con fan-out gonfia somme e conteggi.
  • Risolva il problema pre-aggregando i figli oppure contando e sommando alla granularità corretta, ad esempio con COUNT(DISTINCT).
  • Indichi sempre prima la granularità desiderata: il fan-out è un bug solo quando la viola.

Domande Frequenti

La lezione «Espansione dei join e moltiplicazione delle righe» è gratuita?

Sì — il testo completo di «Espansione dei join e moltiplicazione delle righe» è 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 Coding Interview Prep, passa a CoddyKit PRO. Il corso Coding Interview Prep include 4 lezioni in totale.

Cosa imparerò in «Espansione dei join e moltiplicazione delle righe»?

Capire perché un join può restituire più righe di entrambe le tabelle e come questo viene verificato ai colloqui Eserciti Coding 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 Coding Interview Prep?

Non è richiesta alcuna esperienza precedente. Coding 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 3 di 4.

Quanto tempo richiede la lezione «Espansione dei join e moltiplicazione delle righe»?

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 Coding Interview Prep?

Sì. Ogni lezione Coding 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

  1. Come INNER JOIN abbina le righe
  2. ON e WHERE nei join
  3. Espansione dei join e moltiplicazione delle righe
  4. Unire tre o più tabelle
← Torna a Coding Interview Prep