SQL Academy · Lektion

PostgreSQL DISTINCT ON

Vælg én række pr. gruppe.

Lektion 3 af 413 trin

PostgreSQL DISTINCT ON er en gratis SQL Academy-lektion på CoddyKit. Dette er lektion 3 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 SQL Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. SQL Academy-kurset indeholder 4 lektioner i alt.

Hvad er DISTINCT ON?

PostgreSQL tilbyder en kraftfuld udvidelse af standardens nøgleord DISTINCT, som kaldes DISTINCT ON. Mens almindelig DISTINCT fjerner fuldstændigt identiske rækker, lader DISTINCT ON dig vælge præcis én række pr. gruppe baseret på en eller flere kolonner, du vælger.

Du kan tænke på det sådan: For hver unikke værdi i denne kolonne skal du give mig én række. Det er særdeles nyttigt, når du vil finde den seneste ordre pr. kunde, den højeste score pr. studerende eller den første hændelse pr. kategori.

Grundlæggende DISTINCT ON-syntaks

Syntaksen placerer DISTINCT ON (column) lige efter SELECT. Kolonnen i parentesen definerer grupperingen — PostgreSQL returnerer én række for hver unik værdi i kolonnen.

Eksemplet nedenfor returnerer én række pr. customer_id fra en ordretabel. PostgreSQL vælger, hvilken række der skal returneres, ud fra den efterfølgende ORDER BY-klausul.

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

Oprettelse af eksempeltabeller

Lad os oprette en enkel tabel med navnet orders og indsætte nogle eksempelrækker, så vi kan afprøve DISTINCT ON i praksis. Vi har tre kunder, hver med flere ordrer på forskellige datoer.

CREATE TABLE orders (
  order_id      SERIAL PRIMARY KEY,
  customer_id   INT,
  order_date    DATE,
  total_amount  NUMERIC(10, 2)
);

INSERT INTO orders (customer_id, order_date, total_amount) VALUES
  (1, '2024-01-05', 120.00),
  (1, '2024-03-12', 85.50),
  (1, '2024-06-20', 200.00),
  (2, '2024-02-14', 45.00),
  (2, '2024-05-30', 310.00),
  (3, '2024-04-01', 75.00);

Seneste ordre pr. kunde

Et meget almindeligt anvendelsestilfælde er at finde den seneste ordre for hver kunde. Ved at sortere efter order_date DESC inden for hver customer_id-gruppe vælger DISTINCT ON rækken med den seneste dato.

Bemærk, at ORDER BY-klausulen skal begynde med den eller de samme kolonner, som står i DISTINCT ON. Det er et krav i PostgreSQL.

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

Ældste ordre pr. kunde

Hvis du i stedet vil hente den første (ældste) ordre pr. kunde, skal du blot ændre sorteringsretningen til ASC. Den eneste forskel er rækkefølgen af rækkerne i hver gruppe — DISTINCT ON vælger altid den første række efter sorteringen.

SELECT DISTINCT ON (customer_id)
  customer_id,
  order_id,
  order_date,
  total_amount
FROM orders
ORDER BY customer_id, order_date ASC;

Reglen for ORDER BY

Vigtig regel: Når du bruger DISTINCT ON (col), skal ORDER BY-klausulen begynde med den eller de samme kolonner, som står i DISTINCT ON. Hvis den ikke gør det, udløser PostgreSQL en fejl.

Efter grupperingskolonnen eller -kolonnerne kan du tilføje yderligere sorteringskriterier for at styre, hvilken række i hver gruppe der vælges.

-- Correct: ORDER BY starts with the DISTINCT ON column
SELECT DISTINCT ON (customer_id)
  customer_id, order_date, total_amount
FROM orders
ORDER BY customer_id, total_amount DESC;

-- This would cause an error:
-- ORDER BY order_date DESC  (missing customer_id at the start)

Højeste score pr. studerende

Her er endnu et praktisk eksempel med en tabel med navnet test_scores. Vi vil finde den højeste score, hver studerende nogensinde har opnået. Ved at sortere efter score DESC i hver studerendegruppe returnerer DISTINCT ON kun rækken med den højeste score pr. studerende.

CREATE TABLE test_scores (
  id         SERIAL PRIMARY KEY,
  student_id INT,
  subject    VARCHAR(50),
  score      INT,
  taken_on   DATE
);

INSERT INTO test_scores (student_id, subject, score, taken_on) VALUES
  (101, 'Math',    92, '2024-02-10'),
  (101, 'Math',    78, '2024-04-15'),
  (102, 'Math',    85, '2024-02-10'),
  (102, 'Math',    91, '2024-04-15'),
  (103, 'Math',    67, '2024-02-10');

SELECT DISTINCT ON (student_id)
  student_id, subject, score, taken_on
FROM test_scores
ORDER BY student_id, score DESC;

DISTINCT ON med flere kolonner

Du kan gruppere efter mere end én kolonne ved at angive flere kolonner i DISTINCT ON. Det returnerer én række for hver unik kombination af disse kolonner.

Eksemplet nedenfor vælger den højeste score pr. studerende pr. fag og behandler hvert par af studerende og fag som sin egen gruppe.

INSERT INTO test_scores (student_id, subject, score, taken_on) VALUES
  (101, 'Science', 88, '2024-03-01'),
  (101, 'Science', 95, '2024-05-20'),
  (102, 'Science', 72, '2024-03-01');

SELECT DISTINCT ON (student_id, subject)
  student_id, subject, score, taken_on
FROM test_scores
ORDER BY student_id, subject, score DESC;

Filtrering med WHERE

DISTINCT ON fungerer naturligt sammen med WHERE-klausuler. Filteret anvendes først, hvorefter DISTINCT ON vælger én række pr. gruppe blandt de filtrerede resultater.

Her finder vi den seneste ordre pr. kunde, men kun blandt ordrer på over 100.

SELECT DISTINCT ON (customer_id)
  customer_id,
  order_id,
  order_date,
  total_amount
FROM orders
WHERE total_amount > 100
ORDER BY customer_id, order_date DESC;

DISTINCT ON sammenlignet med GROUP BY

Både DISTINCT ON og GROUP BY kan give én række pr. gruppe, men de tjener forskellige formål:

  • GROUP BY samler rækker og kræver aggregeringsfunktioner (SUM, MAX osv.) for kolonner, der ikke indgår i grupperingen.
  • DISTINCT ON bevarer en faktisk eksisterende række — alle dens kolonner er tilgængelige uden aggregering.

Brug GROUP BY, når du har brug for aggregerede værdier. Brug DISTINCT ON, når du har brug for alle data fra en bestemt række i hver gruppe.

-- GROUP BY: only aggregated columns allowed
SELECT customer_id, MAX(order_date) AS latest_date
FROM orders
GROUP BY customer_id;

-- DISTINCT ON: returns the whole row for that latest date
SELECT DISTINCT ON (customer_id)
  customer_id, order_id, order_date, total_amount
FROM orders
ORDER BY customer_id, order_date DESC;

Brug af DISTINCT ON i en underforespørgsel

Nogle gange har du brug for at anvende yderligere filtrering eller sortering på resultatet fra DISTINCT ON. Fordi den ydre ORDER BY er bundet til grupperingskolonnen, kan du pakke forespørgslen ind i en underforespørgsel (eller CTE) for at anvende en anden sortering på det endelige resultat.

Dette eksempel vælger først den seneste ordre pr. kunde og sorterer derefter det endelige resultat efter total_amount i faldende rækkefølge.

SELECT *
FROM (
  SELECT DISTINCT ON (customer_id)
    customer_id,
    order_id,
    order_date,
    total_amount
  FROM orders
  ORDER BY customer_id, order_date DESC
) AS latest_orders
ORDER BY total_amount DESC;

Hurtigt tjek

Lad os tjekke din forståelse af DISTINCT ON. Læs forespørgslen nedenfor grundigt, og vælg det svar, der bedst beskriver, hvad den returnerer.

SELECT DISTINCT ON (department_id) department_id, employee_name, salary FROM employees ORDER BY department_id, salary DESC;

Opsummering af lektionen

Godt klaret! Her er en opsummering af, hvad du har lært om PostgreSQL DISTINCT ON:

  • DISTINCT ON (col) returnerer præcis én række pr. unik værdi i den eller de angivne kolonner.
  • ORDER BY-klausulen skal begynde med den eller de samme kolonner, som står i DISTINCT ON — den styrer, hvilken række der vælges fra hver gruppe.
  • Du kan bruge flere kolonner: DISTINCT ON (col1, col2) grupperer efter kombinationen af begge.
  • I modsætning til GROUP BY returnerer DISTINCT ON en rigtig række med alle dens oprindelige kolonner — der er ikke brug for aggregering.
  • Pak forespørgslen ind i en underforespørgsel, når du har brug for at sortere det endelige resultat efter en anden kolonne.

DISTINCT ON er en PostgreSQL-specifik funktion og en af de mest elegante måder at løse problemer på, hvor du skal vælge én række pr. gruppe.

Gratis at komme i gang

Lær SQL 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
46
Lektioner
183

Ofte stillede spørgsmål

Er lektionen “PostgreSQL DISTINCT ON” gratis?

Ja — hele teksten til “PostgreSQL DISTINCT ON” 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 SQL Academy-kurset, skal du opgradere til CoddyKit PRO. SQL Academy-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “PostgreSQL DISTINCT ON”?

Vælg én række pr. gruppe. Du øver dig i SQL Academy 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å SQL Academy?

Der kræves ingen tidligere erfaring. SQL Academy 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 3 af 4.

Hvor lang tid tager lektionen “PostgreSQL DISTINCT ON”?

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 SQL Academy-lektion?

Ja. Alle SQL Academy-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. Grundlæggende SELECT DISTINCT
  2. DISTINCT på flere kolonner
  3. PostgreSQL DISTINCT ON
  4. Optælling af entydige værdier
← Tilbage til SQL Academy