Ce face SELECT și DISTINCT ON
Pe lângă interogarea clasică SELECT și eliminarea duplicatelor complete prin SELECT DISTINCT, PostgreSQL oferă extensia SELECT DISTINCT ON (expresie, ...). Aceasta păstrează doar primul rând din fiecare set de rânduri care au aceleași valori pentru expresiile specificate în paranteze.
Pentru ca rezultatul să fie determinist (de exemplu, cea mai recentă comandă a fiecărui client sau cel mai scump produs din fiecare categorie), expresiile din DISTINCT ON trebuie să corespundă primelor coloane din clauza ORDER BY, urmate de coloana care decide care rând este „primul”.
Clauze, operatori și argumente
| Clauză / Operator | Descriere |
|---|---|
SELECT lista_coloane |
Specifică expresiile sau coloanele care vor fi returnate în setul de rezultate. |
DISTINCT |
Elimină rândurile complet identice pe toate coloanele selectate. |
DISTINCT ON (expr, ...) |
Păstrează un singur rând (primul conform ORDER BY) pentru fiecare combinație unică a expresiilor indicate. |
FROM tabel [AS alias] |
Specifică tabelul sursă, vederea (view) sau subinterogarea din care se citesc datele. |
ORDER BY expr, criteriu |
Obligatoriu în practică alături de DISTINCT ON: primele coloane din ORDER BY trebuie să coincidă cu cele din DISTINCT ON. |
Exemple
Exemplul 1: Ultima comandă plasată de fiecare client cu DISTINCT ON
Selectăm cea mai recentă comandă pentru fiecare client_id, ordonând mai întâi după client și apoi descrescător după data comenzii.
SELECT DISTINCT ON (client_id)
client_id,
id AS comanda_id,
total_lei,
plasata_la
FROM comenzi
ORDER BY client_id, plasata_la DESC;
Rezultat interogare
client_id | comanda_id | total_lei | plasata_la
-----------+------------+-----------+---------------------
101 | 5042 | 420.50 | 2025-03-14 16:22:10
102 | 5039 | 189.00 | 2025-03-12 09:15:04
103 | 5051 | 1250.00 | 2025-03-18 19:40:55
(3 rows)
Exemplul 2: Produsul cu cel mai mare preț din fiecare categorie
Folosim DISTINCT ON (categorie) combinat cu ORDER BY categorie, pret DESC pentru a obține liderul de preț din fiecare categorie fără subinterogări complexe.
SELECT DISTINCT ON (categorie)
categorie,
denumire,
pret
FROM produse
WHERE activ = true
ORDER BY categorie, pret DESC, id ASC;
Rezultat interogare
categorie | denumire | pret
------------+------------------------+---------
Laptopuri | ProBook Ultra 16 M3 | 8499.99
Monitoare | Dell UltraSharp 32 4K | 3799.00
Periferice | Tastatură Mecanică Pro | 649.50
(3 rows)
Greșeli frecvente
- Omiterea clauzei
ORDER BYcând foloseștiDISTINCT ON: fără o sortare explicită, PostgreSQL va returna un rând imprevizibil din fiecare grup. - Plasarea în
ORDER BYa unei prime coloane diferite de cea dinDISTINCT ON, ceea ce declanșează eroarea:SELECT DISTINCT ON expressions must match initial ORDER BY expressions.
Comenzi și funcții înrudite
ROW_NUMBER(), RANK() și DENSE_RANK(): Numerotează și clasifică rândurile în interiorul unei partiții fără a le colapsa ca GROUP BY.JOIN și CROSS JOIN LATERAL: Unește tabele și permite subinterogărilor din FROM să facă referire la coloanele tabelelor precedente prin LATERAL.GROUP BY, HAVING și clauza FILTER: Grupează rândurile pentru agregări și aplică condiții individuale pe fiecare funcție agregată prin FILTER (WHERE …).