Как получить идентификаторы, связанные с наиболее частым значением в PostgreSQL? - PullRequest
0 голосов
/ 28 марта 2020

У меня есть следующие данные в моей базе данных PostgreSQL 11 count_tbl (Windows 10 x64 machine).

grp     id     value
1       1      19.7
1       2      19.7
1       3      19.7
1       4      19.7
1       5      19.7
1       6      19.7
1       7      18.8
1       8      18.8
1       9      18.8
1       10     18.8
1       11     18.8
1       12     18.8
2       1      18.6
2       2      18.6
2       3      18.6
2       4      18.6
2       5      18.6
2       6      0.0
2       7      0.0
2       8      0.0
2       9      21.4
2       10     21.4
2       11     0.0
2       12     0.0

Следующий запрос для каждой группы (grp) находит Наиболее частое значение:

Select Distinct on (grp)
    grp,
    case
        when freq > 1
        then value
        else 0.0
    end as freq_val
From
(
    Select
        grp,
        value,
        count(id) as freq
    From count_tbl
    Group by grp, value
    Order by grp
) s1
Order by grp, freq desc, value desc;

Вывод вышеуказанного запроса:

grp    freq_val
1      19.7
2      18.6

Теперь я хотел бы связать наиболее частое значение с соответствующими идентификаторами (например, для grp = 1, наиболее частое значение 19.7 имеет идентификаторы 1, 2, 3, 4, 5, 6), скажем, как integer array. Мой ожидаемый результат:

grp    freq_val     ids
1      19.7         {1,2,3,4,5,6}
2      18.6         {1,2,3,4,5}

Кто-то хочет поразмышлять над этим или предложить, как этого можно достичь?

Ответы [ 2 ]

2 голосов
/ 28 марта 2020

Вы можете использовать оконные функции и агрегирование:

select
    grp,
    value freq_val,
    array_agg(id) ids
from (
    select
        c.*,
        rank() over(partition by grp order by value desc) rn
    from count_tbl
) t
where rn = 1
group by grp, value

Внутренний запрос ранжирует записи, имеющие одинаковые grp, уменьшая value. Затем внешний фильтр запросов в верхних строках для каждой группы и агрегирует.


Редактировать: если вы хотите получить наибольшее значение для каждой группы (вместо самого высокого значения) и связанных с ним идентификаторов, то вы можете агрегат в подзапросе вместо:

select *
from (
    select
        grp,
        value freq_val,
        array_agg(id) ids
        rank() over(partition by grp order by count(*) desc) rn
    from count_tbl
    group by grp, value
) t
where rn = 1
0 голосов
/ 28 марта 2020

Вы можете использовать distinct on. Это забавно, потому что не требует подзапроса:

select distinct on (grp) grp, value, count(*) as freq,
       array_agg(id) over (partition by grp) as ids
from count_tbl
group by grp, value
order by gp, count(*) desc, value desc;

Большинство баз данных требуют подзапроса, либо для использования оконной функции, либо для какого-либо другого сравнения. DISTINCT ON является расширением Postgres.

...