根据group by查询的结果按出现次数分组

Group by number of occurrences based on the result of a group by query

想象一下 table 这样的帖子

posts
---

id
user_id
title

如果我想打印出每个用户的帖子总数,我可能会这样做

SELECT user_id, COUNT(*) as total_posts FROM posts GROUP BY user_id

结果将是这样的:

user_id | total_posts
=====================
1       | 5
2       | 2
5       | 3
8       | 3

现在,如果我想按 total_posts 分组怎么办?所以我正在寻找这样的结果:

total_posts | number_of_users
=============================
5       | 1
2       | 1
3       | 2

是否可以通过 MySQL 执行此操作?我目前正在通过使用 Laravel 的集合来解决这个问题,但是它需要映射 user_id | total_posts table 的每一行,这可能很大,因此可能会占用内存。

您需要 2 个聚合级别:

SELECT total_posts,
       COUNT(*) number_of_users
FROM (
  SELECT user_id, 
         COUNT(*) total_posts 
  FROM posts 
  GROUP BY user_id
) t
GROUP BY total_posts
ORDER BY total_posts DESC;

或者,对于 MySql 8.0+:

SELECT DISTINCT 
       COUNT(*) total_posts,
       COUNT(*) OVER (PARTITION BY COUNT(*)) number_of_users
FROM posts 
GROUP BY user_id
ORDER BY total_posts DESC;

查看简化版 demo.

如果有人在 Laravel 中寻找解决方案,这就是我最终得到的

$posts = DB::query()
    ->fromSub(function ($query) {
        $query->from('posts')
            ->selectRaw('user_id, COUNT(*) as total_posts')
            ->groupBy('user_id');
    }, 't')
    ->selectRaw('total_posts, COUNT(*) number_of_users')
    ->groupBy('total_posts')
    ->orderBy('total_posts', 'asc')
    ->get();