0Pricing
SQL Interview Prep · Lezione

Conservare l'ultima riga per chiave

Il pattern dell'ultimo record per cliente con partizione per chiave e ordinamento per data

Conservare l'ultima riga per chiave è 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.

La domanda sull'elemento più recente per chiave

"Restituisca l'ordine più recente per ogni cliente." "Recuperi lo stato più recente per ogni dispositivo." Questo problema dell'ultima riga per chiave è tra quelli più frequenti nei colloqui SQL, perché ricorre continuamente nel lavoro reale di analisi dei dati.

È un caso specializzato di top-1-per-group: esegua il partitioning per chiave, ordini per timestamp decrescente e mantenga la prima riga. Questa lezione approfondisce il pattern e le sue alternative.

Perché MAX da solo non basta

Una prima risposta allettante è MAX(order_date) raggruppato per cliente. Questo restituisce la data più recente, ma non il resto della riga dell'ordine, l'id dell'ordine, l'importo o lo stato.

Se l'intervistatore vuole l'intera riga più recente, MAX con GROUP BY richiede un join aggiuntivo alla tabella sulla chiave e sulla data massima: la soluzione è più prolissa e può non funzionare correttamente in caso di pari merito. Le funzioni finestra sono più pulite.

-- Gives the date, not the full row
SELECT customer_id, MAX(order_date) AS last_order
FROM orders
GROUP BY customer_id;

Il pattern ROW_NUMBER

Esegua il partitioning per chiave, ordini per timestamp decrescente e la riga più recente otterrà rn = 1. Mantenga solo queste righe e avrà il record completo più recente per ogni chiave.

Questa è la risposta standard. Restituisce esattamente una riga per chiave anche quando i timestamp sono uguali, che è generalmente ciò che implica "la riga più recente".

WITH ranked AS (
  SELECT *,
    ROW_NUMBER() OVER (
      PARTITION BY customer_id
      ORDER BY order_date DESC
    ) AS rn
  FROM orders
)
SELECT customer_id, order_id, order_date, amount
FROM ranked
WHERE rn = 1;

Risoluzione dei pari merito tra timestamp

Due ordini dello stesso cliente possono avere lo stesso order_date (lo stesso giorno o timestamp identici). Senza un criterio di spareggio, la riga che diventa rn = 1 viene scelta arbitrariamente e può cambiare tra un'esecuzione e l'altra.

Aggiunga una chiave secondaria univoca, come order_id DESC, così la riga più recente sarà deterministica. Gli intervistatori verificano in particolare se ha notato questo caso limite.

ROW_NUMBER() OVER (
  PARTITION BY customer_id
  ORDER BY order_date DESC, order_id DESC
) AS rn

L'ultima riga o tutte le righe a pari merito

Decida che cosa significhi "più recente" quando i timestamp sono uguali:

  • Se desidera esattamente una riga per chiave → usi ROW_NUMBER con un criterio di spareggio.
  • Se desidera tutte le righe che condividono il timestamp massimo → usi invece RANK() = 1, che restituisce ogni riga più recente a pari merito.

Porre questa domanda di chiarimento dimostra che comprende la semantica, non soltanto la sintassi.

WITH ranked AS (
  SELECT *,
    RANK() OVER (
      PARTITION BY customer_id ORDER BY order_date DESC
    ) AS rnk
  FROM orders
)
SELECT * FROM ranked WHERE rnk = 1;

L'alternativa con sottoquery correlata

Prima che le funzioni finestra diventassero universali, la soluzione per ottenere l'elemento più recente per chiave usava una sottoquery correlata: si mantiene una riga solo se non esiste un'altra riga della stessa chiave con una data maggiore.

Funziona, ma esegue la query interna per ogni riga, quindi è più lenta su tabelle grandi e poco pratica in caso di pari merito. La citi per dimostrare la propria preparazione, ma preferisca la soluzione con funzione finestra per motivi di prestazioni.

SELECT o.*
FROM orders o
WHERE o.order_date = (
  SELECT MAX(o2.order_date)
  FROM orders o2
  WHERE o2.customer_id = o.customer_id
);

La scorciatoia DISTINCT ON di Postgres

PostgreSQL offre un idioma conciso: DISTINCT ON (key) mantiene la prima riga per chiave in base a ORDER BY. L'ORDER BY deve iniziare con le stesse colonne della chiave, seguite dal criterio di spareggio/timestamp.

È elegante e veloce in Postgres, ma non è portabile. Lo citi come vantaggio specifico del dialetto, mantenendo ROW_NUMBER come scelta predefinita portabile.

SELECT DISTINCT ON (customer_id)
  customer_id, order_id, order_date, amount
FROM orders
ORDER BY customer_id, order_date DESC, order_id DESC;

Ultima riga con una condizione

Le domande reali aggiungono filtri: "l'ordine completato più recente per ogni cliente". Applichi il filtro prima del ranking, così vengono numerate solo le righe che soddisfano il criterio.

Inserisca la condizione nella WHERE della query interna, che viene eseguita prima della funzione finestra, quindi selezioni rn = 1 nella query esterna. Filtrare dopo il ranking restituirebbe la riga sbagliata.

WITH ranked AS (
  SELECT *,
    ROW_NUMBER() OVER (
      PARTITION BY customer_id ORDER BY order_date DESC, order_id DESC
    ) AS rn
  FROM orders
  WHERE status = 'completed'
)
SELECT * FROM ranked WHERE rn = 1;

Esempio svolto: stato più recente del dispositivo

Una tabella status_log registra device_id, status e logged_at. Per ottenere lo stato attuale di ogni dispositivo, esegua il partitioning per device_id, ordini per logged_at DESC e mantenga rn = 1.

Questo è il meccanismo alla base dei dashboard che mostrano lo "stato attuale" di molte entità a partire da un log di eventi append-only. La stessa ricetta permette di ottenere query per l'ultimo prezzo, l'ultima posizione e l'ultima versione.

WITH latest AS (
  SELECT device_id, status, logged_at,
    ROW_NUMBER() OVER (
      PARTITION BY device_id ORDER BY logged_at DESC
    ) AS rn
  FROM status_log
)
SELECT device_id, status, logged_at
FROM latest
WHERE rn = 1;

Note sulle prestazioni

Elementi da citare per dimostrare una preparazione da senior:

  • Un indice su (customer_id, order_date DESC) permette al motore di leggere in modo efficiente la riga più recente per ogni chiave.
  • L'approccio con funzione finestra esegue una sola scansione della tabella; la sottoquery correlata no.
  • In Postgres, DISTINCT ON può usare lo stesso indice ed è spesso l'opzione più veloce su una singola tabella.
  • Per i log di eventi con molte operazioni di inserimento, valuti una tabella materializzata degli elementi "più recenti", aggiornata in modo incrementale.

Errori comuni

Faccia attenzione a questi casi:

  • Usare MAX(date) e restituire solo la data, non l'intera riga.
  • Dimenticare il criterio di spareggio, ottenendo risultati non deterministici quando le date coincidono.
  • Filtrare in base alla condizione dopo il ranking, selezionando così una riga che avrebbe dovuto essere esclusa.
  • Confondere "una sola riga più recente" (ROW_NUMBER) con "tutte le righe più recenti a pari merito" (RANK).

Verifica rapida

Scelga la query corretta per ottenere l'ultima riga per chiave.

Riepilogo: ultima riga per chiave

Il pattern: PARTITION BY key, ORDER BY timestamp DESC (più un criterio di spareggio univoco), mantenendo rn = 1.

  • MAX(date) restituisce la data, non l'intera riga.
  • Aggiunga sempre un criterio di spareggio per ottenere un risultato deterministico.
  • Usi RANK() = 1 se desidera tutte le righe a pari merito con il timestamp più recente.
  • Le condizioni di filtro devono trovarsi nella query interna, prima del ranking.
  • In Postgres, DISTINCT ON è un'alternativa concisa e veloce, specifica del dialetto.

Domande Frequenti

La lezione «Conservare l'ultima riga per chiave» è gratuita?

Sì — il testo completo di «Conservare l'ultima riga per chiave» è 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 «Conservare l'ultima riga per chiave»?

Il pattern dell'ultimo record per cliente con partizione per chiave e ordinamento per data 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 «Conservare l'ultima riga per chiave»?

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

  1. Righe Top-N per gruppo con ROW_NUMBER
  2. Gestire le parità nelle Top-N
  3. Deduplicare le righe in sicurezza
  4. Conservare l'ultima riga per chiave
← Torna a SQL Interview Prep