在 postgresql 排名的每个组上获取不同的 LIMIT

问题描述

要从每个组中获取 2 行,我可以使用 ROW_NUMBER() 和条件 <= 2 最后但我的问题是如果我想对每个组获得不同的限制,例如 section_id 1,1 的 3 行2 行和 1 行 3?

给定下表:

db=# SELECT * FROM xxx;
 id | section_id | name
----+------------+------
  1 |          1 | A
  2 |          1 | B
  3 |          1 | C
  4 |          1 | D
  5 |          2 | E
  6 |          2 | F
  7 |          3 | G
  8 |          2 | H
(8 rows)

我得到每个 section_id 的前 2 行(按 name 排序),即结果类似于:

 id | section_id | name
----+------------+------
  1 |          1 | A
  2 |          1 | B
  5 |          2 | E
  6 |          2 | F
  7 |          3 | G
(5 rows)

当前查询

SELECT
  * 
FROM (
  SELECT
    ROW_NUMBER() OVER (PARTITION BY section_id ORDER BY name) AS r,t.*
  FROM
    xxx t) x
WHERE
  x.r <= 2;

解决方法

只需修改您的 where 子句:

with numbered as (
  select row_number() over (partition by section_id
                                order by name) as r,t.*
    from xxx t
)
select *
  from numbered
 where (section_id = 1 and r <= 3)
    or (section_id = 2 and r <= 1)
    or (section_id = 3 and r <= 1);
,

创建一个包含节限制的表,然后加入。最大的优势在于,当需要新部分或限制更改时,维护减少到单个表更新,并且成本很低。见example

select s.section_id,s.name  
  from (select section_id,name,row_number() over (partition by section_id order by name) rn
          from sections
       )  s 
  left join section_limits sl on (sl.section_id = s.section_id) 
where 
  s.rn <= coalesce(sl.limit_to,2);