【问题标题】:How do I get IDs associated with the most frequent value in PostgreSQL?如何获取与 PostgreSQL 中最常见值关联的 ID?
【发布时间】:2020-07-09 03:18:40
【问题描述】:

我的 PostgreSQL 11 数据库 count_tbl(Windows 10 x64 机器)中有以下数据。

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

现在,我想将最常见的值与相应的 ID 相关联(例如,对于 grp = 1,最常见的值 19.7 的 ID 为 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}

是否有人愿意对此进行反思或建议如何实现?

【问题讨论】:

    标签: sql arrays postgresql group-by count


    【解决方案1】:

    您可以使用窗口函数和聚合:

    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
    

    内部查询通过减少value 对具有相同grp 的记录进行排名。然后,外部查询过滤每个 froup 和聚合的顶部行。


    编辑:如果您想要每个组中出现次数最多的值(而不是最高值)及其关联的 id,那么您可以在子查询中进行聚合:

    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
    

    【讨论】:

    • 您好,感谢您的努力!我测试了你的代码。这是输出:1, 19.7, {1,2,3,4,5,6}2, 21.4, {9,10}。对于第 2 组,最常见的值是 21.4 如果我们查看样本数据,这不是真的希望它有意义吗? :)
    • 我认为,您的代码会找到最高值,而不是最重复或常见的值。显然,19.7 和 21.4 是代码输出中给出的最高值。
    • @khajlk:我明白你的意思。我用另一个查询更新了我的答案。
    • 上述查询的输出是重复 ID,因为相同数量的 ID 可以保持相同的值:1,19.7, {1,2,3,4,5,6}, 1, 18.8 ,{7,8,9,10,11,12}2, 0.0, {6,7,8,11,12}, 2, 18.6, {1,2,3,4 ,5}。我添加了 'Distinct on (grp)' 和 'Order by grp, value desc' 我得到了预期的输出。关心更新您的第二个代码?我很高兴接受这个答案:)。
    【解决方案2】:

    您可以使用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 扩展。

    【讨论】:

    • 您好,有两件事:(1)也许我无法在问题中说清楚......因为我不仅需要频繁的值。我还需要将频率值与相应的 id 相关联。 (2) 您的代码给出了输出:1, 19.7, 62, 0.0, 5,这与我的第一个输出不同。您的代码只给出了最常见的值,在第 2 组中,值 18.6 和 0.0 具有相同的计数(即 5),我的查询选择 18.6 作为最常见的值,我认为这更有意义..
    • @khajlk 。 . .如果您想要一个决胜局,只需将另一个密钥添加到order by。我添加了value desc,以便在出现平局时获得更大的价值。
    • 不过,数组值是这样的 {7,8,4,1,9,3,2,6,10,12,11,5} 和 {1,4,7,2,6,12,5,3,9,8,10,11} 组 1 和 2 :(
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-17
    • 1970-01-01
    • 2020-10-12
    • 2011-02-08
    • 1970-01-01
    • 2021-01-26
    相关资源
    最近更新 更多