postgresql 仅获取Postgres中每种类型的最高计数

xoshrz7s  于 2023-06-29  发布在  PostgreSQL
关注(0)|答案(2)|浏览(125)

假设我有一张table,上面有孩子和他们的玩具。

CREATE TABLE kids_toys (
  kid_name character varying,
  toy_type character varying,
  toy_name character varying
);

| 玩具类型|玩具名称| toy_name |
| - -----|- -----| ------------ |
| 熊|呸| Pooh |
| 熊|Pooh2| Pooh2 |
| 熊|辛巴| Simba |
| 汽车|弗鲁姆| Vroom |
| 娃娃|莎莉| Sally |
| 汽车|哔哔声| Beeps |
| 汽车|速度快| Speedy |
| 汽车|红色| Red |
我想得到一个最受欢迎的玩具类型为每个孩子的名单,由孩子分组。所以结果会是
| 玩具类型|计数| count |
| - -----|- -----| ------------ |
| 熊|三个| 3 |
| 汽车|2| 2 |
假设Postgres 15作为引擎,我该如何查询来做到这一点?我一直在如何生成计数上卡住,但然后只从每个孩子的计数中获取最大结果。

eqzww0vc

eqzww0vc1#

首先,按kid_nametoy_type分组,找出每个孩子有多少玩具。
然后,添加一个row_number窗口函数,该窗口函数仅由kid_name分区,并按count降序排列,以从最高计数到最低计数查找每个单独孩子的每个toy_type的位置
最后,只过滤row_num = 1记录
此外,如果您希望每个孩子都有前3个玩具,则可以使用row_num <= 3代替。

select kid_name, toy_type, cnt
from
(select kid_name, toy_type, cnt, row_number() over(partition by kid_name order by cnt desc) as row_num
  from (
    select kid_name, toy_type, count(*) as cnt
    from kids_toys
    group by kid_name, toy_type
  ) as grouped
) as with_row_num
where row_num = 1
ep6jt1vc

ep6jt1vc2#

在Postgres中,我推荐使用distinct on,它可以在一次传递中完成工作:

select distinct on (kid_name) kid_name, toy_type, count(*) cnt
from kids_toys
group by kid_name, toy_type
order by kid_name, count(*) desc, toy_type

该查询按孩子和玩具对数据集进行分组。然后distinct on确保每个孩子只返回一条记录; order by子句将每个孩子最喜欢的玩具放在第一位。如果有领带,第一个玩具被挑选(按字母顺序)。
如果你想保持关系(Postgres的distinct on不能做到),我们可以使用rank()fetch with ties来代替:

select kid_name, toy_type, count(*) cnt
from kids_toys
group by kid_name, toy_type
order by rank() over(partition by kid_name order by count(*) desc)
fetch first row with ties

相关问题