Как выбрать идентификатор с максимальной датой группы по категории в PostgreSQL?

88

Например, я хотел бы выбрать идентификатор с максимальной датой для группы по категориям, результат: 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

Могу я узнать, как это сделать в PostgreSQL?

user2412043
источник
4
Всегда разумно включать свою версию PostgreSQL.
Erwin Brandstetter

Ответы:

141

Это идеальный вариант использования DISTINCT ON(расширение стандарта Postgres DISTINCT):

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

Будьте осторожны с порядком сортировки по убыванию. Если столбец может иметь значение NULL, вы можете добавить NULLS LAST:

DISTINCT ONмаксимально просто и быстро. Подробное объяснение в этом соответствующем ответе:

Для больших таблиц рассмотрите альтернативный подход:

Оптимизация производительности для многих строк на category:

Эрвин Брандштеттер
источник
Выглядит здорово, но уверены ли вы, что это всегда будет работать?
Atherion
@Tixel: Совершенно верно. Для получения более подробной информации перейдите по ссылкам.
Эрвин Брандштеттер,
21

Попробуй это:

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

См. Этот SQLFiddle

Химаншу Джансари
источник
1
Есть еще один вариант использования оконной функции rank ().
Дени де Бернарди
@ user1735921: вы получите все столбцы из Table1. Вы можете выбрать то, что хотите.
Himanshu Jansari
15

Другой подход - использовать first_valueоконную функцию: http://sqlfiddle.com/#!12/7a145/14

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

... хотя я подозреваю, что предложение hims056 обычно работает лучше, если присутствуют соответствующие индексы.

Третье решение:

SELECT
  id
FROM (
  SELECT
    id,
    row_number() OVER (PARTITION BY "category" ORDER BY "date" DESC) AS rownum
  FROM Table1
) x
WHERE rownum = 1;
Крэйг Рингер
источник
-5

ВЫБРАТЬ ИД ИЗ ТАБЛИЦЫ ГРУППА ПО коту ИМЕЕТ МАКСИМУМ (дата)

Немилосердный
источник
2
Это недопустимый синтаксис и не отвечает на вопрос.
Эрвин Брандштеттер,
4
Это не работает на PostgreSQL, но работает с Sqlite
владаман