2016-08-31 5 views
0

Я хочу, чтобы ограничить записи в каждой группе, так что, когда я их агрегирование в объект JSON в выбранном-заявлении, он принимает только N conversations с hightest countОграничить результаты каждой группы

Любые идеи?

Мой запрос:

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) 
      from apps a 
      left join conversations c on c.app_id = a.id 
      where started_at_url is not null and c.started_at::date > (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' 
     group by dt.id 

ответ

1

Ваша задача аналогична задаче 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.

+0

Отличный ответ, спасибо – Tarlen