Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/75.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 如何获得按评论数量分组的用户数量';你做了什么?_Sql_Postgresql_Count_Group By - Fatal编程技术网

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;