SQL Academy · Lektion

PostgreSQL DISTINCT ON

Välj en rad per grupp.

Lektion 3 av 413 steg

PostgreSQL DISTINCT ON är en gratis lektion i SQL Academy på CoddyKit. Detta är lektion 3 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för SQL Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i SQL Academy innehåller totalt 4 lektioner.

Vad är DISTINCT ON?

PostgreSQL erbjuder ett kraftfullt tillägg till standardnyckelordet DISTINCT som kallas DISTINCT ON. Medan vanlig DISTINCT tar bort helt identiska rader låter DISTINCT ON er välja exakt en rad per grupp baserat på en eller flera kolumner som ni väljer.

Tänk på det så här: ”För varje unikt värde i den här kolumnen, ge mig en rad.” Det är mycket användbart när ni vill hitta den senaste ordern per kund, den högsta poängen per student eller den första händelsen per kategori.

Grundläggande syntax för DISTINCT ON

Syntaxen placerar DISTINCT ON (column) direkt efter SELECT. Kolumnen inom parentesen definierar grupperingen — PostgreSQL returnerar en rad för varje unikt värde i den kolumnen.

Exemplet nedan returnerar en rad per customer_id från en ordertabell. PostgreSQL väljer vilken rad som ska returneras baserat på den efterföljande ORDER BY-klausulen.

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

Konfigurera exempeltabeller

Låt oss skapa en enkel tabell med namnet orders och lägga in några exempelrader så att vi kan prova DISTINCT ON i praktiken. Vi har tre kunder, var och en med flera ordrar på olika datum.

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);

Senaste ordern per kund

Ett mycket vanligt användningsfall är att hitta den senaste ordern för varje kund. Genom att sortera order_date DESC inom varje customer_id-grupp väljer DISTINCT ON raden med det senaste datumet.

Observera att ORDER BY-klausulen måste börja med samma kolumn(er) som anges i DISTINCT ON. Detta är ett 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;

Tidigaste ordern per kund

Om ni i stället vill hämta den första (äldsta) ordern per kund ändrar ni helt enkelt sorteringsriktningen till ASC. Den enda skillnaden är radordningen inom varje grupp — DISTINCT ON väljer alltid den första raden efter sorteringen.

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

Regeln för ORDER BY

Viktig regel: När ni använder DISTINCT ON (col) måste ORDER BY-klausulen börja med samma kolumn(er) som anges i DISTINCT ON. Om den inte gör det genererar PostgreSQL ett fel.

Efter grupperingskolumnen eller grupperingskolumnerna kan ni lägga till valfria ytterligare sorteringskriterier för att styra vilken rad i varje grupp som väljs.

-- 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ögsta poängen per student

Här är ytterligare ett praktiskt exempel med tabellen test_scores. Vi vill hitta den högsta poäng som varje student någonsin har uppnått. Genom att sortera score DESC inom varje studentgrupp returnerar DISTINCT ON endast raden med högst poäng per student.

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 flera kolumner

Ni kan gruppera efter mer än en kolumn genom att ange flera kolumner i DISTINCT ON. Då returneras en rad för varje unik kombination av dessa kolumner.

Exemplet nedan väljer den högsta poängen per student och ämne, där varje par (student, ämne) behandlas som en egen grupp.

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 fungerar naturligt tillsammans med WHERE-klausuler. Filtret tillämpas först, och därefter väljer DISTINCT ON en rad per grupp bland de filtrerade resultaten.

Här hittar vi den senaste ordern per kund, men endast för ordrar över 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 jämfört med GROUP BY

Både DISTINCT ON och GROUP BY kan skapa en rad per grupp, men de fyller olika funktioner:

  • GROUP BY slår ihop rader och kräver aggregatfunktioner (SUM, MAX och så vidare) för kolumner som inte ingår i grupperingen.
  • DISTINCT ON behåller en faktisk befintlig rad — alla dess kolumner är tillgängliga utan aggregering.

Använd GROUP BY när ni behöver aggregerade värden. Använd DISTINCT ON när ni behöver alla data från en viss rad i varje grupp.

-- 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;

Använda DISTINCT ON i en underfråga

Ibland behöver ni filtrera eller sortera resultatet från DISTINCT ON ytterligare. Eftersom den yttre ORDER BY är bunden till grupperingskolumnen kan ni kapsla in frågan i en underfråga (eller CTE) för att använda en annan sortering av det slutliga resultatet.

I det här exemplet väljs först den senaste ordern per kund, och därefter sorteras slutresultatet efter total_amount i fallande ordning.

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;

Snabbtest

Kontrollera era kunskaper om DISTINCT ON. Läs frågan nedan noggrant och välj det svar som bäst beskriver vad den returnerar.

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

Sammanfattning av lektionen

Bra jobbat! Här är en sammanfattning av vad ni har lärt er om PostgreSQL DISTINCT ON:

  • DISTINCT ON (col) returnerar exakt en rad per unikt värde av de angivna kolumnerna.
  • ORDER BY-klausulen måste börja med samma kolumn(er) som anges i DISTINCT ON — den styr vilken rad som väljs från varje grupp.
  • Ni kan använda flera kolumner: DISTINCT ON (col1, col2) grupperar efter kombinationen av båda.
  • Till skillnad från GROUP BY returnerar DISTINCT ON en faktisk rad med alla sina ursprungliga kolumner — ingen aggregering behövs.
  • Kapsla in frågan i en underfråga när ni behöver sortera slutresultatet efter en annan kolumn.

DISTINCT ON är en PostgreSQL-specifik funktion och ett av de elegantaste sätten att lösa problem där ni ska välja en rad per grupp.

Gratis att börja

Lär dig SQL med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
46
Lektioner
183

Vanliga frågor

Är lektionen ”PostgreSQL DISTINCT ON” gratis?

Ja – hela texten till ”PostgreSQL DISTINCT ON” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i SQL Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i SQL Academy innehåller totalt 4 lektioner.

Vad lär jag mig i ”PostgreSQL DISTINCT ON”?

Välj en rad per grupp. Ni övar på SQL Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig SQL Academy?

Du behöver inga förkunskaper. Utbildningen i SQL Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 3 av 4.

Hur lång tid tar lektionen ”PostgreSQL DISTINCT ON”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här SQL Academy-lektionen?

Ja. Varje SQL Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Grunderna i SELECT DISTINCT
  2. DISTINCT på flera kolumner
  3. PostgreSQL DISTINCT ON
  4. Räkna unika värden
← Tillbaka till SQL Academy