Pivot dinamici con colonne sconosciute
Generazione delle colonne pivot quando le categorie non sono note in anticipo.
Pivot dinamici con colonne sconosciute è una lezione Coding 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 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.
La domanda difficile sui pivot
Ogni pivot statico, sia che utilizzi un'aggregazione con CASE, PIVOT di SQL Server o crosstab di Postgres, presenta la stessa limitazione: è necessario elencare le colonne di output quando si scrive la query.
Ma cosa succede quando le categorie non sono note, ad esempio nomi di prodotti che cambiano ogni settimana o una colonna per ogni mese attivo? Si tratta di un pivot dinamico, una domanda da colloquio per profili senior perché il SQL semplice non può restituire un risultato la cui lista di colonne viene determinata a runtime.
Perché il solo SQL non può farlo
SQL è tipizzato staticamente a livello di set di risultati: il pianificatore deve conoscere le colonne e i relativi tipi prima dell'esecuzione. Una singola query non può dire crei una colonna per ogni valore trovato.
La tecnica universale consiste quindi nel generare il testo SQL in due passaggi: prima si interrogano le categorie distinte, poi si costruisce una stringa contenente la query di pivot a partire da esse e si esegue quella stringa.
Passaggio 1: raccogliere le categorie
Il primo passaggio consiste in una query normale che elenca i valori distinti che diventeranno colonne. In genere li si ordina per ottenere una disposizione stabile delle colonne.
Questo risultato alimenta il passaggio di costruzione della stringa. In un sistema reale si esegue questa query, si acquisiscono le righe e si assembla la query successiva a partire da esse.
SELECT DISTINCT quarter
FROM sales
ORDER BY quarter;
-- e.g. Q1, Q2, Q3, Q4Passaggio 2: costruire la lista delle colonne
Successivamente, si trasformano questi valori in una lista separata da virgole di espressioni CASE (oppure in nomi tra parentesi quadre per PIVOT). I database offrono funzioni di aggregazione di stringhe per eseguire questa operazione direttamente in SQL.
In Postgres la funzione è string_agg; in MySQL GROUP_CONCAT; in SQL Server STRING_AGG oppure il più vecchio espediente FOR XML PATH.
-- Postgres: build the SELECT-list fragment
SELECT string_agg(
format('SUM(CASE WHEN quarter = %L THEN amount END) AS %I',
quarter, quarter),
', '
)
FROM (SELECT DISTINCT quarter FROM sales ORDER BY 1) q;Passaggio 3: assemblare ed eseguire
Si concatena il frammento generato in una stringa contenente la query completa, quindi la si esegue dinamicamente: EXECUTE in PL/pgSQL, sp_executesql in SQL Server oppure PREPARE/EXECUTE in MySQL.
Questo è il cuore di un pivot dinamico: SQL scrive SQL e poi lo esegue.
-- SQL Server pattern
DECLARE @cols NVARCHAR(MAX), @sql NVARCHAR(MAX);
SELECT @cols = STRING_AGG(QUOTENAME(quarter), ',')
FROM (SELECT DISTINCT quarter FROM sales) q;
SET @sql = N'SELECT region, ' + @cols + '
FROM (SELECT region, quarter, amount FROM sales) s
PIVOT (SUM(amount) FOR quarter IN (' + @cols + ')) p;';
EXEC sp_executesql @sql;Esempio completo in PostgreSQL
In Postgres si racchiudono i tre passaggi in un blocco DO o in una funzione. Si costruisce la lista delle colonne con string_agg, la si inserisce nella query e si esegue quest'ultima con EXECUTE.
Poiché le colonne del risultato non sono note fino al runtime, una funzione che restituisce questo risultato utilizza spesso RETURNS SETOF record oppure restituisce le righe come json, che il chiamante espande successivamente.
DO $do$
DECLARE
cols text;
qry text;
BEGIN
SELECT string_agg(
format('SUM(CASE WHEN quarter=%L THEN amount END) AS %I', quarter, quarter), ', ')
INTO cols
FROM (SELECT DISTINCT quarter FROM sales ORDER BY 1) q;
qry := format('SELECT region, %s FROM sales GROUP BY region', cols);
EXECUTE qry;
END $do$;MySQL con istruzioni preparate
MySQL non dispone di un operatore pivot, quindi i pivot dinamici costruiscono una stringa di aggregazione condizionale con GROUP_CONCAT, quindi la eseguono tramite un'istruzione preparata.
GROUP_CONCAT ha un limite di lunghezza (group_concat_max_len) che chi conduce il colloquio potrebbe menzionare; se si hanno molte categorie, lo si aumenti.
SET @sql = NULL;
SELECT GROUP_CONCAT(DISTINCT
CONCAT('SUM(CASE WHEN quarter=''', quarter,
''' THEN amount END) AS ', QUOTE(quarter))
) INTO @sql FROM sales;
SET @sql = CONCAT('SELECT region, ', @sql,
' FROM sales GROUP BY region');
PREPARE st FROM @sql; EXECUTE st; DEALLOCATE PREPARE st;Il rischio di SQL injection
Poiché si concatenano valori dei dati in SQL eseguibile, i pivot dinamici comportano un rischio di injection. Se un valore di categoria contiene un apice o testo malevolo, può danneggiare o dirottare la query generata.
Utilizzi sempre gli strumenti sicuri del motore per fare l'escaping di identificatori e letterali: format('%I', ...) e %L in Postgres, QUOTENAME in SQL Server. Non inserisca mai valori non elaborati direttamente nella stringa.
-- Safe quoting prevents injection / breakage
-- Postgres: %I identifier, %L literal
format('SUM(CASE WHEN k=%L THEN v END) AS %I', cat, cat)
-- SQL Server: QUOTENAME(cat)Restituire colonne non note
Un'altra difficoltà è che il chiamante non può conoscere in anticipo la struttura del risultato. Tra le strategie comunemente accettate nei colloqui ci sono:
- Restituire le righe come
JSONe lasciare che sia il livello applicativo a espandere le chiavi. - Fare in modo che la procedura stampi o costruisca la query, per poi eseguirla in un secondo passaggio.
- Eseguire il pivot finale nel codice dell'applicazione (pandas, strumento di BI) una volta note le categorie.
Non esiste un modo semplice per restituire colonne arbitrarie da una singola chiamata statica.
Esempio svolto: pivot per prodotto
Supponiamo che i prodotti entrino ed escano dal catalogo e che il report richieda una colonna dei ricavi per ogni prodotto attualmente presente in sales. Non è possibile codificare l'elenco in modo rigido, quindi lo si genera. Postgres rende il procedimento leggibile: si costruisce il frammento CASE con string_agg e un quoting sicuro, lo si inserisce nella query e poi si usa EXECUTE.
Spieghi il procedimento a chi conduce il colloquio: individuare i prodotti, formattare ciascuno in una colonna tra virgolette, assemblare ed eseguire. La stessa struttura si applica a qualsiasi motore; cambiano solo gli strumenti di supporto.
DO $do$
DECLARE cols text; qry text;
BEGIN
SELECT string_agg(
format('SUM(CASE WHEN product=%L THEN amount END) AS %I',
product, product), ', ')
INTO cols
FROM (SELECT DISTINCT product FROM sales ORDER BY 1) p;
qry := format('SELECT region, %s FROM sales GROUP BY region', cols);
EXECUTE qry;
END $do$;Quando evitare i pivot dinamici
I candidati migliori sanno quando non eseguire questa operazione in SQL. Il SQL dinamico è più difficile da leggere, testare, proteggere e memorizzare nella cache. Spesso la risposta migliore è:
- Restituire il formato lungo da SQL ed eseguire il pivot nell'applicazione o nel livello di reporting.
- Se l'insieme di categorie è ridotto e cambia lentamente, utilizzare un pivot statico e aggiornarlo occasionalmente.
Riservi i pivot dinamici agli insiemi di categorie realmente aperti e in continua evoluzione.
Verifica rapida
Verifichi il motivo fondamentale per cui esistono i pivot dinamici.
Riepilogo
I pivot dinamici gestiscono insiemi di colonne non noti:
- I pivot statici non funzionano perché le colonne del risultato devono essere fissate prima dell'esecuzione.
- Schema: interrogare le categorie distinte, costruire una stringa SQL per il pivot ed eseguirla dinamicamente.
- Utilizzare
string_agg/GROUP_CONCAT/STRING_AGGper costruire la lista delle colonne. - Eseguire l'escaping dei valori (
%I/%L,QUOTENAME) per evitare SQL injection. - Spesso è più pulito restituire il formato lungo ed eseguire il pivot nel livello applicativo.
Domande Frequenti
La lezione «Pivot dinamici con colonne sconosciute» è gratuita?
Sì — il testo completo di «Pivot dinamici con colonne sconosciute» è 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 «Pivot dinamici con colonne sconosciute»?
Generazione delle colonne pivot quando le categorie non sono note in anticipo. 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 4 di 4.
Quanto tempo richiede la lezione «Pivot dinamici con colonne sconosciute»?
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
- Pivot con aggregazione condizionale
- Sintassi PIVOT e crosstab specifica del database
- Trasformare le colonne in righe
- Pivot dinamici con colonne sconosciute