LINUX.ORG.RU

Запрос с группировкой, выбор максимума из группы.

 ,


0

2

Есть таблица с полями url и created_at.

В таблице есть множество записей с одинаковым url. Мне нужно получить записи со самым старшим created_at, для каждой группы с одинаковым url. Т.е., имея:

    url         | created_at
    ------------------------
    abc         |          1
    abc         |          2
    abc         |          2
    def         |          3
    def         |          0

Получить:

    url         | created_at
    ------------------------
    abc         |          2
    def         |          3

Пробовал сделать это так:

    SELECT *
    FROM items
    GROUP BY url
    HAVING created_at = MAX(created_at)

Получаю:

    ERROR:  column "items.id" must appear in the GROUP BY clause or be used in an aggregate function

Попробовал то же самое немного иначе:

    SELECT MAX(created_at) AS last_created_At, *
    FROM items
    GROUP BY url
    HAVING created_at = last_created_at

Получил:

    ERROR:  column "last_created_at" does not exist
    LINE 4: HAVING created_at = last_created_at`

Похоже я неправильно понимаю как работает GROUP BY HAVING. Как мне достичь желаемого без вложенного запроса?

Без вложенного запроса имхо никак.

Т.к. вот у тебя группировка по url из 3-х записей -

id url  created_at
1  abc  2
2  abc  0
3  abc  1

группировка сворачивает эти строки в одну ->

url -> abc, created_at -> 2, а id какой постгрессу выбрать?

только аггрегирующую функцию или подзапрос.

pi11 ★★★★★ ()

Похоже я неправильно понимаю как работает GROUP BY HAVING

having фильтрует уже сгруппированные результаты, а как их сгруппировать, ты постгрессу не говоришь.

pi11 ★★★★★ ()
Ответ на: комментарий от nt_crasher

Неудобно записывать с запрос с помощью рельсового arel, пользуюсь бо хочу поиметь композицию запросов.

vladimir-vg ★★ ()
Ответ на: комментарий от grondek

Ну тогда, действительно, чем не устраивает подзапрос?

Есть вот такое шаманство (если я все правильно написал):

SELECT DISTINCT ON (url) url, last_value(created_at) over( PARTITION BY url ORDER BY created_at DESC ), last_value(<еще колонка>) over( PARTITION BY url ORDER BY created_at DESC ), last_value(<еще колонка>) over( PARTITION BY url ORDER BY created_at DESC ), ... FROM items;

grondek ()
select * from items as a where not exists (select * from items as b where a.created_at < b.created_at and a.url=b.url)
maxcom ★★★★★ ()
Ответ на: комментарий от vladimir-vg

и еще вопрос: какое поведение ты ожидаешь, если появилось 2 записи с одинаковым максимальным created_at для какого-то урла?

Goganchic ★★ ()
Ответ на: комментарий от Goganchic

Решил так:

SELECT *
FROM items
WHERE created_at = (SELECT MAX(created_at)
                    FROM items AS t
                    WHERE t.url = items.url)

если появилось 2 записи с одинаковым максимальным created_at

Взять любой из них. Добавил DISTINCT ON (url) для этого.

vladimir-vg ★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.