Sql 如何获得按评论数量分组的用户数量';你做了什么?
我想根据用户发表的评论数对其进行分组Sql 如何获得按评论数量分组的用户数量';你做了什么?,sql,postgresql,count,group-by,Sql,Postgresql,Count,Group By,我想根据用户发表的评论数对其进行分组 [User]: ID [Comment]: ID, UserID 因此,如果用户A发表了1条评论,用户B发表了1条评论,用户C发表了2条评论,那么输出将是: 0 comments => 0 users 1 comment => 2 users (A+B) 2 comments => 1 user (C) 您将如何查询它?这取决于您的特定数据库结构,但假设您有一个用户表和一个注释表: users table: id: serial n
[User]: ID
[Comment]: ID, UserID
因此,如果用户A发表了1条评论,用户B发表了1条评论,用户C发表了2条评论,那么输出将是:
0 comments => 0 users
1 comment => 2 users (A+B)
2 comments => 1 user (C)
您将如何查询它?这取决于您的特定数据库结构,但假设您有一个用户表和一个注释表:
users table:
id: serial
name: text
comments table:
id: serial
user_id: integer (foreign key to the users table)
comment: text
您可以计算每个用户对此查询的评论数:
SELECT users.id, users.name, count(comments.id) as comment_cnt
FROM users LEFT JOIN
comments ON users.id = comments.user_id
GROUP BY users.id, users.name
然后,可以在嵌套查询中使用此查询的结果来计算每个注释数的用户数:
SELECT comment_cnt, count(*) FROM
(SELECT users.id, users.name, count(comments.id) as comment_cnt
FROM users LEFT JOIN
comments ON users.id = comments.user_id
GROUP BY users.id, users.name) AS comment_cnts
GROUP BY comment_cnt;
我不知道有什么优雅的方法来填补空白,在给定数量的评论中没有用户,但是临时表和另一个嵌套级别可以工作:
CREATE TABLE wholenumbers (num integer);
INSERT INTO wholenumbers VALUES (0), (1), (2), (3), (4), (5), (6);
SELECT num as comment_cnt, COALESCE(user_cnt,0) as user_cnt
FROM wholenumbers
LEFT JOIN (SELECT comment_cnt, count(*) AS user_cnt
FROM ( SELECT users.id, users.name, count(comments.id) AS comment_cnt
FROM users LEFT JOIN comments ON users.id = comments.user_id
GROUP BY users.id, users.name) AS comment_cnts
GROUP BY comment_cnt) AS user_cnts ON wholenumbers.num = user_cnts.comment_cnt
ORDER BY num;
基于表格布局的构建:
要点
- 首先,统计每个用户的评论(
msg\u ct
)。只要引用完整性由外键强制执行,就根本不需要加入users
表来聚合每个用户的注释。只需计算注释中的行数
接下来,按消息计数计数用户(用户
)
- 我在a中这样做,因为我在最终查询中使用了两次派生表。
首先用于动态生成从最小值到最大值的所有计数,包括间隙。
然后将表左键连接到,得到最终结果
- 计数从0开始(在我的更新之后)。如果你想让它从最小的实际<代码> MSGYCT 开始,请考虑我在编辑历史中的第一个草稿。
- 与之密切相关的回答,解释基本知识:
统计没有评论的用户数
正如@ClaytonC所评论的,上述答案不包括没有评论的用户
要解决此问题(如果您确实需要),请在开始时左键连接到用户
右键:
WITH cte AS (
SELECT msg_ct, count(*) AS users
FROM (
SELECT count(c.user_id) AS msg_ct
FROM users u
LEFT JOIN comments c ON c.user_id = u.id
GROUP BY u.id
) sub
GROUP BY 1
)
SELECT ...
或,因为加入只是为了找到没有评论的用户,我们可能会更便宜:计算所有用户并减去有评论的用户(无论如何我们都会处理这些用户):
查询变得有点复杂,但对于大型表来说可能更快。不确定。使用EXPLAIN ANALYZE
进行测试(如果您能对测试结果发表评论,我将不胜感激)。太棒了,它可以工作了!小的额外要求:如果没有用户发表一定数量的评论(例如,0=>20个用户,1=>0个用户[我们想要这个],2=>5个用户),你将如何填补计数空白?我不知道有什么优雅的方法可以做到这一点。您可以手动创建一个临时表,其中包含一个整数列和n行,每个行中有一个整数1、2、3、4。。。不管你喜欢多少。然后可以添加另一个嵌套级别。我将把修改后的查询添加到我的答案中。谢谢@ErwinBrandstetter。我不知道那件事。您的解决方案是否显示有0条评论的用户数?@Claytoc:很好,谢谢。现在是了。这比从最小数量开始更有意义。再次感谢@ErwinBrandstetter。看起来您还需要更改WITH查询以引用users表,否则无法在没有任何注释的情况下知道有多少用户。目前,您的解决方案根本不引用用户表。您需要提供相关的表布局以及问题和您尝试过的内容(即使它不起作用)。你已经有足够长的时间了,应该知道基本的知识。嗨,欧文!事实上,我不知道这个规则,很高兴你这么说。我假设一对多关联是如此基本和标准,以至于不需要定义表布局。无论如何,谢谢你的反馈!:)有许多微妙的变化。非空、唯一、主键约束、数据类型、基数、行宽度、索引、值的频率。。。它们对最佳解决方案都很重要。最好使用\d tbl
提供在psql中获得的实际表布局的(相关部分)。更好的是,提供一个(随机的例子)。伟大的答案,一如既往!非常感谢。
WITH cte AS (
SELECT msg_ct, count(*) AS users
FROM (
SELECT count(c.user_id) AS msg_ct
FROM users u
LEFT JOIN comments c ON c.user_id = u.id
GROUP BY u.id
) sub
GROUP BY 1
)
SELECT ...
WITH cte AS (
SELECT msg_ct, count(*)::int AS users
FROM (
SELECT count(*)::int AS msg_ct
FROM comments
GROUP BY user_id
) sub
GROUP BY 1
)
, agg AS (
SELECT max(msg_ct) AS max_ct -- maximum for generate_series
,((SELECT count(*) FROM users) - sum(users))::int AS users
-- quiet rest with 0 comments
FROM cte
)
SELECT 0 AS msg_ct, users FROM agg -- users with 0 comments
UNION ALL
SELECT msg_ct, COALESCE(users, 0)
FROM (SELECT generate_series(1, max_ct) AS msg_ct FROM agg) g
LEFT JOIN cte USING (msg_ct)
ORDER BY 1;