Можно ли упростить этот запрос, который группирует пользователей по количеству размещенных комментариев? - PullRequest
1 голос
/ 27 апреля 2020

В этом запросе используются две таблицы, и все, что имеет значение в результате, - это количество пользователей, которые до сих пор не оставили ни одного комментария. В таблице user, конечно, есть столбец id, который является внешним ключом в таблице comment, обозначенным столбцом user_id.

Первый супер-простой запрос группирует пользователей по тому, есть ли у них какие-либо комментарии. Он выводит две строки (строку с количеством пользователей, у которых есть комментарии, и строку с количеством пользователей, у которых нет комментариев), с двумя столбцами (количество пользователей и то, отправили ли они какие-либо комментарии).

SELECT 
    COUNT(id) AS user_count, 
    IF( id IN ( SELECT user_id FROM `comment` ), 1, 0) AS has_comment
FROM `user`
GROUP BY has_comment

Пример того, как выходные данные будут выглядеть здесь:

+------------+-------------+
| user_count | has_comment |
+------------+-------------+
| 150        | 0           |
| 140        | 1           |
+------------+-------------+

Теперь вот мой вопрос. Здесь я хочу получить немного больше информации, сгруппировав этих пользователей в 3 группы:

  1. Пользователи, которые не оставили комментариев
  2. Пользователи, которые оставили меньше 10 комментариев
  3. Пользователи, которые опубликовали 10 или более комментариев

И лучший запрос, который я знаю, как написать для этой цели, заключается в следующем, который работает, но, к сожалению, выполняет 4 подзапроса и имеет 2 производные таблицы:

SELECT 
   COUNT(id) AS user_count,
   CASE
      WHEN id IN ( SELECT user_id FROM ( SELECT COUNT(user_id) AS comment_count, user_id FROM `comment` GROUP BY user_id HAVING comment_count >= 10 ) AS a) THEN '10 or more'
      WHEN id IN ( SELECT user_id FROM ( SELECT COUNT(user_id) AS comment_count, user_id FROM `comment` GROUP BY user_id HAVING comment_count < 10 ) AS b) THEN 'less than 10'
      ELSE 'none'
   END AS has_comment
FROM `user`
GROUP BY has_comment

Пример вывода здесь будет примерно таким:

+------------+-------------+
| user_count | has_comment |
+------------+-------------+
| 150        | none        |
| 130        | less than 10|
| 100        | 10 or more  |
+------------+-------------+

Этот второй запрос; можно ли его написать проще и эффективнее, и все же дать такой же результат? (потенциально может быть даже расширен на большее количество таких «групп»)

1 Ответ

1 голос
/ 27 апреля 2020

Вы можете использовать два уровня агрегации:

select
    count(*) no_users,
    case
        when no_comments = 0 then 'none'
        when no_comments < 10 then 'less than 10'
        else '10 or more'
    end has_comment
from (
    select 
        u.id, 
        (select count(*) from comments c where c.user_id = u.id) no_comments
    from users u
) t
group by has_comment
order by no_comments

Подзапрос подсчитывает, сколько комментариев имеет каждый пользователь (вы также можете express это с left join и агрегацией); затем внешний запрос классифицирует и подсчитывает количество пользователей по количеству комментариев.

...