Forberedelse til kodeinterviews · Lektion

Bevar den seneste række pr. nøgle

Mønsteret for den seneste post pr. kunde med partitionering efter nøgle og sortering efter dato

Lektion 4 af 413 trin

Bevar den seneste række pr. nøgle er en gratis Forberedelse til kodeinterviews-lektion på CoddyKit. Dette er lektion 4 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i Forberedelse til kodeinterviews, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Forberedelse til kodeinterviews-kurset indeholder 4 lektioner i alt.

Spørgsmålet om den nyeste pr. nøgle

"Returnér den seneste ordre for hver kunde." "Find den nyeste status for hver enhed." Dette problem med den nyeste række pr. nøgle er en af de hyppigste SQL-opgaver til jobsamtaler, fordi det hele tiden dukker op i praktisk analysearbejde.

Det er en specialiseret top-1 pr. gruppe: Opdel efter nøglen, sortér efter tidsstemplet i faldende rækkefølge, og behold den første række. Denne lektion gennemgår mønsteret og dets alternativer.

Hvorfor MAX alene ikke er nok

Et fristende første svar er MAX(order_date) grupperet efter kunde. Det giver den seneste dato, men ikke resten af ordrens række, ordre-id'et, beløbet eller status.

Hvis intervieweren vil have hele den seneste række, kræver MAX med GROUP BY en ekstra join tilbage til tabellen på nøglen og den maksimale dato. Det er omstændeligt og kan give problemer ved ens værdier. Vinduesfunktioner er enklere.

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

Mønsteret med ROW_NUMBER

Opdel efter nøglen, sortér efter tidsstemplet i faldende rækkefølge, så får den seneste række rn = 1. Behold kun disse rækker, så har du den fulde nyeste post pr. nøgle.

Dette er standardsvaret. Det returnerer præcis én række pr. nøgle, selv når tidsstemplerne er ens, hvilket normalt er det, der menes med "den seneste række".

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;

Håndtering af ens tidsstempler

To ordrer for den samme kunde kan have samme order_date (samme dag eller identiske tidsstempler). Uden en sekundær sorteringskolonne er det vilkårligt, hvilken der bliver rn = 1, og resultatet kan ændre sig mellem kørsler.

Tilføj en entydig sekundær nøgle som order_id DESC, så den seneste række bliver deterministisk. Interviewere undersøger specifikt, om du har bemærket dette særtilfælde.

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

Seneste række eller alle ens værdier

Beslut, hvad "seneste" betyder, når tidsstemplerne er ens:

  • Hvis du vil have præcis én række pr. nøgle → ROW_NUMBER med en sekundær sorteringskolonne.
  • Hvis du vil have alle rækker, der deler det maksimale tidsstempel → brug i stedet RANK() = 1, som returnerer alle seneste rækker med samme værdi.

Et sådant afklarende spørgsmål viser, at du forstår betydningen, ikke kun syntaksen.

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;

Alternativet med korreleret underforespørgsel

Før vinduesfunktioner blev almindelige, brugte man en korreleret underforespørgsel til at finde den nyeste række pr. nøgle: Behold kun en række, hvis ingen anden række for den samme nøgle har en senere dato.

Det virker, men den indre forespørgsel køres for hver række, så det er langsommere på store tabeller og besværligt ved ens værdier. Nævn det for at vise bredden, men foretræk vinduesfunktionen af hensyn til ydeevnen.

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

Genvej med Postgres DISTINCT ON

PostgreSQL har en kort konstruktion: DISTINCT ON (key) beholder den første række pr. nøgle i henhold til ORDER BY. ORDER BY skal begynde med de samme nøglekolonner og derefter indeholde sorteringskriteriet for ens værdier og tidsstemplet.

Det er elegant og hurtigt i Postgres, men kan ikke bruges på tværs af databasetyper. Nævn det som en bonus, der er specifik for en SQL-dialekt, mens du bruger ROW_NUMBER som din standard, der kan bruges på tværs af systemer.

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

Nyeste række med en betingelse

Virkelige spørgsmål indeholder ekstra filtre: "den seneste afsluttede ordre pr. kunde". Anvend filteret før rangordningen, så kun kvalificerende rækker får et nummer.

Placér betingelsen i WHERE i den indre forespørgsel, som køres før vinduesfunktionen, og vælg derefter rn = 1 i den ydre forespørgsel. Hvis du filtrerer efter rangordningen, får du den forkerte række.

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;

Gennemgået eksempel: Nyeste enhedsstatus

En tabel med navnet status_log registrerer device_id, status og logged_at. Hvis du vil hente den aktuelle status for hver enhed, skal du opdele efter device_id, sortere efter logged_at DESC og beholde rn = 1.

Det er grundlaget for dashboards, der viser den "aktuelle tilstand" for mange enheder ud fra en hændelseslog, der kun tilføjes til. Den samme opskrift bruges til forespørgsler efter nyeste pris, placering og version.

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;

Bemærkninger om ydeevne

Formuleringer, der giver ekstra point på seniorniveau:

  • Et indeks på (customer_id, order_date DESC) gør det muligt for motoren effektivt at læse den nyeste række pr. nøgle.
  • Vinduestilgangen gennemgår tabellen én gang; den korrelerede underforespørgsel gør ikke.
  • DISTINCT ON i Postgres kan bruge det samme indeks og er ofte den hurtigste løsning på en enkelt tabel.
  • For hændelseslogge med mange tilføjelser kan du overveje en materialiseret tabel med de "nyeste" værdier, som opdateres trinvist.

Almindelige fejl

Hold øje med disse fejl:

  • At bruge MAX(date) og kun returnere datoen i stedet for hele rækken.
  • At glemme den sekundære sorteringskolonne, hvilket giver ikke-deterministiske resultater, når datoerne er ens.
  • At filtrere på betingelsen efter rangordningen, så der kan blive valgt en række, som burde være udelukket.
  • At forveksle "én nyeste række" (ROW_NUMBER) med "alle seneste rækker med samme værdi" (RANK).

Hurtigt tjek

Vælg den korrekte forespørgsel til den nyeste række pr. nøgle.

Opsummering: Nyeste række pr. nøgle

Mønsteret er: PARTITION BY key, ORDER BY timestamp DESC (plus en entydig sekundær sorteringskolonne), behold rn = 1.

  • MAX(date) giver datoen, ikke hele rækken.
  • Tilføj altid en sekundær sorteringskolonne for at gøre resultatet deterministisk.
  • Brug RANK() = 1, hvis du vil have alle rækker med samme seneste tidsstempel.
  • Filterbetingelser hører til i den indre forespørgsel, før rangordningen.
  • Postgres' DISTINCT ON er et kort, hurtigt alternativ, der er specifikt for en SQL-dialekt.
Gratis at komme i gang

Lær Forberedelse til kodeinterviews med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
90
Lektioner
360

Ofte stillede spørgsmål

Er lektionen “Bevar den seneste række pr. nøgle” gratis?

Ja — hele teksten til “Bevar den seneste række pr. nøgle” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af Forberedelse til kodeinterviews-kurset, skal du opgradere til CoddyKit PRO. Forberedelse til kodeinterviews-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Bevar den seneste række pr. nøgle”?

Mønsteret for den seneste post pr. kunde med partitionering efter nøgle og sortering efter dato Du øver dig i Forberedelse til kodeinterviews med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Forberedelse til kodeinterviews?

Der kræves ingen tidligere erfaring. Forberedelse til kodeinterviews på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 4 af 4.

Hvor lang tid tager lektionen “Bevar den seneste række pr. nøgle”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Forberedelse til kodeinterviews-lektion?

Ja. Alle Forberedelse til kodeinterviews-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Top-N-rækker pr. gruppe med ROW_NUMBER
  2. Håndtering af ligheder i Top-N
  3. Sikker fjernelse af dubletter
  4. Bevar den seneste række pr. nøgle
← Tilbage til Forberedelse til kodeinterviews