Ваша задача аналогична задаче GROUPWISE-максимум, и есть много решений этого.
Фильтрация row_number
функция окна
простой заключается в использовании row_number()
оконной функции и отфильтровать только для строк, что результат < N (с использованием 5 в качестве примера):
select
dt.id as app_id,
json_build_object(
'rows', array_agg(
json_build_object(
'url', dt.started_at_url,
'count', dt.count
)
)
) as data
from (
select
a.id, c.started_at_url,
count(c.id) as count,
row_number() over(partition by a.id order by count(c.id) desc) as rn
from apps a
left join conversations c on c.app_id = a.id
where started_at_url is not null and c.started_at > (current_date - (7 || ' days')::interval)::date
group by a.id, c.started_at_url
order by count desc
) as dt
where
dt.id = 'ASnYW1-RgCl0I'
and dt.rn <= 5 /* get top 5 only */
group by dt.id
Использование латерального
Другой вариант заключается в использовании LATERAL
и LIMIT
вернуть только результаты, которые вы заинтересованы в:
select
a.id as app_id,
json_build_object(
'rows', array_agg(
json_build_object(
'url', dt.started_at_url,
'count', dt.count
)
)
) as data
form
apps a, lateral(
select
c.started_at_url,
count(*) as count
from
conversations c
where
c.app_id = a.id /* here is why lateral is necessary */
and c.started_at_url is not null
and c.started_at > (current_date - (7 || ' days')::interval)::date
group by
c.started_at_url
order by
count(*) desc
limit 5 /* get top 5 only */
) as dt
where
a.id = 'ASnYW1-RgCl0I'
group by
a.id
OBS: Я этого не пробовал, поэтому может быть опечатка. Вы можете предоставить образцы данных, если хотите провести тестирование.
OBS 2: Если вы действительно фильтрации по app_id
на вашем окончательном запросе, то вам не нужно даже, что пункт GROUP BY
.
Отличный ответ, спасибо – Tarlen