Подсчитать количество оценок - PullRequest
0 голосов
/ 28 августа 2018

Я хочу рассчитать количество каждой рейтинговой группы по заданному диапазону дат. Я написал следующий запрос, который работает идеально:

SELECT c.day, 
(SELECT COUNT(DISTINCT user_id) FROM ratings r WHERE DATE(r.created_at) = c.day AND r.rating = 1 AND r.campaign_id = 2) AS rating1s,
(SELECT COUNT(DISTINCT user_id) FROM ratings r WHERE DATE(r.created_at) = c.day AND r.rating = 2 AND r.campaign_id = 2) AS rating2s,
(SELECT COUNT(DISTINCT user_id) FROM ratings r WHERE DATE(r.created_at) = c.day AND r.rating = 3 AND r.campaign_id = 2) AS rating3s,
(SELECT COUNT(DISTINCT user_id) FROM ratings r WHERE DATE(r.created_at) = c.day AND r.rating = 4 AND r.campaign_id = 2) AS rating4s,
(SELECT COUNT(DISTINCT user_id) FROM ratings r WHERE DATE(r.created_at) = c.day AND r.rating = 5 AND r.campaign_id = 2) AS rating5s
FROM calendar c
WHERE c.day >= '2018-08-01'
GROUP BY c.day
ORDER BY c.day
LIMIT 0, 31

Но это не оптимизированный способ из-за 5 подзапросов, а запрос занимает почти 2 минуты на моем локальном хосте, как я могу оптимизировать этот запрос? Пример вывода прилагается, и мне нужен такой же вывод. enter image description here

Ответы [ 2 ]

0 голосов
/ 28 августа 2018

Вот запрос, который я сделал, используя ответ @ Гордона:

SELECT  DATE(r.created_at),
       COUNT(
           DISTINCT
           CASE 
             WHEN r.rating = 1 
             THEN  user_id
             ELSE 0
           END
       ) as rating1s,
       COUNT(
           DISTINCT
           CASE 
             WHEN r.rating = 2 
             THEN  user_id
             ELSE 0
           END
       ) as rating2s,
       COUNT(
           DISTINCT
           CASE 
             WHEN r.rating = 3 
             THEN  user_id
             ELSE 0
           END
       ) as rating3s,
       COUNT(
           DISTINCT
           CASE 
             WHEN r.rating = 4
             THEN  user_id
             ELSE 0
           END
       ) as rating4s,
       COUNT(
           DISTINCT
           CASE 
             WHEN r.rating = 5 
             THEN  user_id
             ELSE 0
           END
       ) as rating5s

FROM ratings r
WHERE r.campaign_id = 2 AND
      DATE(r.created_at) >= '2018-08-01'
GROUP BY DATE(r.created_at)

Это все еще не оптимизировано, но намного лучше, чем мое первоначальное решение.

0 голосов
/ 28 августа 2018

Вы можете перефразировать это как условное агрегирование:

SELECT DATE(r.created_at),
       COUNT(DISTINCT CASE WHEN r.rating = 1 THEN r.user_id END) as raging_1,
       COUNT(DISTINCT CASE WHEN r.rating = 2 THEN r.user_id END) as raging_2,
       COUNT(DISTINCT CASE WHEN r.rating = 3 THEN r.user_id END) as raging_3,
       COUNT(DISTINCT CASE WHEN r.rating = 4 THEN r.user_id END) as raging_4,
       COUNT(DISTINCT CASE WHEN r.rating = 5 THEN r.user_id END) as raging_5
FROM ratings r
WHERE r.campaign_id = 2 AND
      r.created_at >= '2018-08-01'
GROUP BY DATE(r.created_at);

COUNT(DISTINCT) может быть дорогим. Удалите это, если можете. В противном случае может быть быстрее сделать DISTINCT один раз:

SELECT dte,
       SUM( r.rating = 1 ) as raging_1,
       SUM( r.rating = 2 ) as raging_2,
       SUM( r.rating = 3 ) as raging_3,
       SUM( r.rating = 4 ) as raging_4,
       SUM( r.rating = 5 ) as raging_5
FROM (SELECT DISTINCT user_id, rating, DATE(r.created_at) as dte
      FROM ratings r
      WHERE r.campaign_id = 2 AND
            r.created_at >= '2018-08-01'
     ) urd
GROUP BY dte;

Возвращает строки для каждого дня, который имеет хотя бы один рейтинг. Если в некоторые дни будут все нули, вам понадобится какое-то внешнее соединение. Это практически ничего не добавляет к производительности, поэтому ее можно использовать, если работает одно из перечисленных выше решений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...