¿Cómo seleccionar la identificación con el grupo de fecha máxima por categoría en PostgreSQL?

88

Por ejemplo, me gustaría seleccionar id con grupo de fecha máxima por categoría, el resultado es: 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

¿Puedo saber cómo hacer esto en PostgreSQL?

usuario2412043
fuente
4
Siempre es aconsejable incluir su versión de PostgreSQL.
Erwin Brandstetter

Respuestas:

141

Este es un caso de uso perfecto para DISTINCT ON(extensión específica de Postgres del estándar DISTINCT):

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

Cuidado con el orden de clasificación descendente. Si la columna puede ser NULL, es posible que desee agregar NULLS LAST:

DISTINCT ONes el más simple y rápido. Explicación detallada en esta respuesta relacionada:

Para tablas grandes, considere este enfoque alternativo:

Optimización del rendimiento para muchas filas por category:

Erwin Brandstetter
fuente
Parece genial, pero ¿estás absolutamente seguro de que funciona siempre?
Atherion
@Tixel: Absolutamente. Siga los enlaces para obtener más detalles.
Erwin Brandstetter
21

Prueba este:

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

Ver este SQLFiddle

Himanshu Jansari
fuente
1
Hay otra opción que usa la función de ventana rank ().
Denis de Bernardy
@ user1735921: Obtendrá todas las columnas de Table1. Puedes elegir el que quieras.
Himanshu Jansari
15

Otro enfoque es utilizar la first_valuefunción de ventana: http://sqlfiddle.com/#!12/7a145/14

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

... aunque sospecho que la sugerencia de hims056 normalmente funcionará mejor cuando estén presentes los índices apropiados.

Una tercera solución es:

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

SELECCIONE ID DEL GRUPO tbl POR CAT QUE TIENEN MAX (fecha)

Despiadado
fuente
2
Esta es una sintaxis ilegal y no responde a la pregunta.
Erwin Brandstetter
4
Esto no funciona en PostgreSQL pero funciona con Sqlite
vladaman