Come selezionare l'ID con il gruppo di date massime per categoria in PostgreSQL?


91

Ad esempio, vorrei selezionare l'ID con il gruppo di date massime per categoria, il risultato è: 7, 2, 6

id  category  date
1   a         2013-01-01
2   b         2013-01-03
3   c         2013-01-02
4   a         2013-01-02
5   b         2013-01-02
6   c         2013-01-03
7   a         2013-01-03
8   b         2013-01-01
9   c         2013-01-01

Posso sapere come farlo in PostgreSQL?


4
È sempre consigliabile includere la propria versione di PostgreSQL.
Erwin Brandstetter

Risposte:


145

Questo è un caso d'uso perfetto per DISTINCT ONun'estensione specifica di Postgres dello standard DISTINCT:

SELECT DISTINCT ON (category)
       id  -- , category, date  -- any other column (expression) from the same row
FROM   tbl
ORDER  BY category, date DESC;

Attento con l'ordinamento decrescente. Se la colonna può essere NULL, potresti aggiungere NULLS LAST:

DISTINCT ONè semplice e veloce. Spiegazione dettagliata in questa risposta correlata:

Per le tabelle grandi con molte righe per categoryconsiderare un approccio alternativo:


Sembra fantastico, ma sei assolutamente sicuro che funzioni sempre?
Atherion

@Tixel: assolutamente. Segui i link per maggiori dettagli.
Erwin Brandstetter

21

Prova questo:

SELECT t1.* FROM Table1 t1
JOIN 
(
   SELECT category, MAX(date) AS MAXDATE
   FROM Table1
   GROUP BY category
) t2
ON T1.category = t2.category
AND t1.date = t2.MAXDATE

Vedi questo SQLFiddle


1
C'è un'altra opzione che usa la funzione della finestra rank ().
Denis de Bernardy

@ user1735921: otterrai tutte le colonne da Table1. Puoi scegliere quello che vuoi.
Himanshu Jansari

16

Un altro approccio consiste nell'usare la first_valuefunzione finestra: http://sqlfiddle.com/#!12/7a145/14

SELECT DISTINCT
  first_value("id") OVER (PARTITION BY "category" ORDER BY "date" DESC) 
FROM Table1
ORDER BY 1;

... anche se sospetto che il suggerimento di hims056 in genere funzionerà meglio se sono presenti gli indici appropriati.

Una terza soluzione è:

SELECT
  id
FROM (
  SELECT
    id,
    row_number() OVER (PARTITION BY "category" ORDER BY "date" DESC) AS rownum
  FROM Table1
) x
WHERE rownum = 1;

-5

SELEZIONA ID DA tbl GROUP PER gatto HAVING MAX (data)


2
Questa è una sintassi illegale e non risponde alla domanda.
Erwin Brandstetter

4
Questo non funziona su PostgreSQL ma funziona con Sqlite
vladaman
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.