在 GROUP BY 中按行数获取前 N 行

Posted

技术标签:

【中文标题】在 GROUP BY 中按行数获取前 N 行【英文标题】:Get the top N rows by row count in GROUP BY 【发布时间】:2021-11-27 17:32:38 【问题描述】:

我正在查询一个记录表,以查找哪些用户是我对某些记录类型的主要记录创建者。我的查询的基本起点如下所示:

SELECT recordtype, createdby, COUNT(*)
FROM recordtable
WHERE recordtype in (...)
GROUP BY recordtype, createdby
ORDER BY recordtype, createdby DESC

但是有很多用户创建了记录 - 我想进一步缩小范围。

我添加了HAVING COUNT(*) > ...,但有些记录类型只有几条记录,而另一些则有数百条记录。如果我这样做HAVING COUNT(*) > 10,我不会看到所有 9 条“XYZ”类型的记录都是由同一个人创建的,但我必须滚动浏览每个人,这些人只创建了 15、30、50 等3,500 条“ABC”类型的记录。

我只想要每种记录类型的前 5、10 名左右的创建者。

我发现了一些解决问题的“选择组中前 N 个”部分的问题,但我不知道如何将它们应用于我需要的内容。我能找到的答案是“排名依据”列是存储在表中的值,而不是聚合值。

(例如:“每个国家/地区人口最多的城市是什么?”,数据如下所示:)

Country       City     Population
United States New York 123456789
United States Chicago  123456789
France        Paris    123456789

我不知道如何应用我见过的用于回答这个问题的方法(主要是row_number())来获得COUNT(*) 的前 N ​​个。

【问题讨论】:

【参考方案1】:

这是一种方法,可以在每组中获取前 10 行:

select * from(
    select *, row_number() over (partition by recordtype order by cnt desc) rn
    from (
       SELECT recordtype, createdby, COUNT(*) cnt
       FROM recordtable
       WHERE recordtype in (...)
       GROUP BY recordtype, createdby
    )t 
)t where rn <= 10 

【讨论】:

做到了。谢谢!我确实注意到一个错字:partition recordtype by.【参考方案2】:

如果我理解得很好,您想获得数量最多的前 N ​​条记录。您可以使用这样的子查询来实现这一点(我想您正在使用 mysql 或 PostGRESQL 或 db2,在其他数据库引擎中,限制和偏移量可能会有所不同,例如在 sqlserver 中通过 select top n * from...

SELECT A.recordtype, A.createdby, A.total FROM (
    SELECT recordtype, createdby, COUNT(*) as total
    FROM recordtable
    WHERE recordtype in (...)
    GROUP BY recordtype, createdby
) AS A ORDER BY recordtype, createdby, total DESC
LIMIT 10 OFFSET 0

limit 是你想要在结果页中的记录数,offset 是在进入结果页之前要跳过的记录数。

如果你使用 sqlserver,它可能看起来像这样(还有一种方法可以应用偏移量,你可以看看这里SQL Server OFFSET and LIMIT)

SELECT TOP 10 A.recordtype, A.createdby, A.total FROM (
    SELECT recordtype, createdby, COUNT(*) as total
    FROM recordtable
    WHERE recordtype in (...)
    GROUP BY recordtype, createdby
) AS A ORDER BY recordtype, createdby, total DESC

对于分组结果,您可以查看此帖子http://www.silota.com/docs/recipes/sql-top-n-group.html

所以要分组获取前 10 条记录,不仅是第一个我混合了这个答案,还有下面的链接和@eshirvana 的方法

SELECT * FROM (
    SELECT *, row_number() OVER (PARTITION recordtype BY ORDER BY total DESC) rn
    FROM (
        SELECT recordtype, createdby, COUNT(*) as total
        FROM recordtable
        WHERE recordtype in (...)
        GROUP BY recordtype, createdby
    ) t
) t WHERE total <= 10 

【讨论】:

第一个查询没有给出我正在寻找的结果。我想要 每个组中的前 N ​​条记录。所有这些查询给我的是一种记录类型的前 10 个创建者,按用户名的字母顺序排列。该链接也是我试图弄清楚的一个链接,但它没有回答“top N by count”部分。 我更新了答案以适应@eshirvana 的答案以完成答案。

以上是关于在 GROUP BY 中按行数获取前 N 行的主要内容,如果未能解决你的问题,请参考以下文章

按行数聚合值

如何按行数限制(或截断)文本文件?

在矩阵中按行获取所有可能的组合

使用 GROUP BY 和 ORDER BY pl/sql 获取结果集的 N 到 M 行 [重复]

在 Laravel 5 中按行排序并限制结果

优化 PostgreSql 查询以获取找到的记录总数和基于多个 group by 的分页所需的有限行数