Как рассчитать процент от предыдущей недели в совокупном запросе? - PullRequest
0 голосов
/ 19 января 2019

Я поставил перед собой задачу, которая казалась изначально тривиальной. Это не так для моего мозга разработчика.

Рассмотрим следующее простое представление, используемое для проверки cron, который запрашивает подмножество 200 000 операторов каждую субботу.

Это выглядит следующим образом:

mysql> SELECT
    ->     DATE_FORMAT(s.created, "%Y-%m-%d") as "Date",
    ->     count(s.id) AS "Accounts credited",
    ->     sum(s.withdrawal) "Total Credited"
    ->   --  100 * (sum(s.withdrawal) - sum(prev.withdrawal)) 
         --   / sum(prev.withdrawal) "Difference in %"
    ->     FROM statements s
    -> --    LEFT JOIN prev
    -> --        s.created - interval 7 DAY
    ->  --     ON prev.created = s.created - interval 7 DAY 
        --     AND (prev.status_id = 'OPEN' 
        --     OR prev.status_id = 'PENDING')
    ->     WHERE (s.status_id = 'OPEN' OR  s.status_id = 'PENDING')
    ->     GROUP BY YEAR(s.created), MONTH(s.created), DAY(s.created)
    ->       ORDER BY s.created DESC
    ->     LIMIT 8;

+------------+-------------------+----------------+
| Date       | Accounts credited | Total Credited |
+------------+-------------------+----------------+
| 2019-01-19 |             18175 |        3173.68 |
| 2019-01-12 |             18135 |        4768.43 |
| 2019-01-05 |             17588 |        6968.49 |
| 2018-12-29 |             17893 |        5404.18 |
| 2018-12-22 |             17353 |        7048.18 |
| 2018-12-15 |             16893 |        7181.34 |
| 2018-12-08 |             16220 |        9547.09 |
| 2018-12-01 |             15476 |        7699.59 |
+------------+-------------------+----------------+
8 rows in set (0.79 sec)

Как есть, запрос эффективен и практичен. Я просто хотел бы добавить столбец, difference in percentage, из итогов предыдущей недели, как видно из - закомментированного кода.

Я пробовал разные подходы, но из-за GROUP BY добавление встроенного столбца для получения sum(withdrawal) предыдущей недели делает запрос выполненным ... навсегда.

Затем я попробовал подход LEFT JOIN, но это та же проблема, очевидно. Я думаю, что добавленный JOIN должен получить сумму предыдущей недели для каждой строки внешнего выбора.

У меня тогда была (не такая умная) идея опроса моего взгляда, даже тогда, похоже, у меня возникла бы та же проблема.

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

Есть ли элегантный способ подсчета процентов по такому запросу?

Будет ли более оптимальной хранимая процедура или какой-нибудь другой подход, не являющийся "простым-sql"?

Ответы [ 4 ]

0 голосов
/ 19 января 2019

Это ваш запрос:

select date_format(s.created, '%Y-%m-%d') as "Date",
       count(*) AS "Accounts credited",
       sum(s.withdrawal) "Total Credited"
from statements s
where s.status_id in ('OPEN', 'PENDING')
group by date_format(s.created, '%Y-%m-%d')
order by s.created desc
limit 8;

В MySQL, пожалуй, самое простое решение - это переменные. Однако из-за правил, связанных с переменными MySQL, это немного сложно:

select s.*,
       (case when (@new_prev := @prev) = NULL then NULL  -- never gets here
             when (@prev := Total_Credited) = NULL then NULL -- never gets here
             else @new_prev
        end) as previous_week_Total_Credited
from (select date_format(s.created, '%Y-%m-%d') as "Date",
             count(*) AS Accounts_credited,
             sum(s.withdrawal) as Total_Credited
      from statements s
      where s.status_id in ('OPEN', 'PENDING')
      group by date_format(s.created, '%Y-%m-%d')
      order by "Date" desc
     ) s cross join
     (select @prev := NULL) params
 limit 8;

Затем вы можете просто использовать это как подзапрос для окончательного расчета.

0 голосов
/ 19 января 2019

Если вы довольны своим исходным запросом, вам может понадобиться подобранный подзапрос, подобный этому.

select t.*,
         (select totalcredited from t t1 where t1.dt < t.dt order by t1.dt desc limit 1) prev,
         (
         totalcredited / (select totalcredited from t t1 where t1.dt < t.dt order by t1.dt desc limit 1)  * 100
         ) -100 as chg
from  (your query) as t;
0 голосов
/ 19 января 2019

Я заметил ошибку в моем предыдущем примере, так что вот обновление.ПРИМЕЧАНИЕ: запрос сравнивает текущую неделю с предыдущей.Я надеюсь, что это то, что вам нужно.

SELECT
    Date,
    SUM(CASE week WHEN 0 THEN accounts_credited ELSE 0 END) AS 'Accounts credited',
    SUM(CASE week WHEN 0 THEN total_credited ELSE 0 END) AS 'Total Credited',
    100 * (
        SUM(CASE week WHEN 0 THEN total_credited ELSE 0 END) - SUM(CASE week WHEN 1 THEN total_credited ELSE 0 END)
    ) / SUM(CASE week WHEN 1 THEN total_credited ELSE 0 END) AS 'Difference in %'
FROM
(SELECT
    DATE_FORMAT(created, '%Y-%m-%d') as 'Date',
    COUNT(id) AS 'accounts_credited',
    SUM(withdrawal) 'total_credited',
    0 AS 'week'
FROM 
    statements
WHERE 
    status_id IN ('OPEN','PENDING')
AND
    YEARWEEK(created, 1) = YEARWEEK(CURDATE(), 1)
GROUP BY 
    DATE(created)
UNION
SELECT
    DATE_FORMAT(created, '%Y-%m-%d') as 'Date',
    COUNT(id) AS 'accounts_credited',
    SUM(withdrawal) 'total_credited',
    1 AS 'week'
FROM 
    statements
WHERE 
    status_id IN ('OPEN','PENDING')
AND
    (
    DATE(created) >= CURDATE() - INTERVAL DAYOFWEEK(CURDATE())+6 DAY
    AND 
    DATE(created) < CURDATE() - INTERVAL DAYOFWEEK(CURDATE())-1 DAY
    )
GROUP BY 
    DATE(created)
) AS tmp
ORDER BY Date
GROUP BY Date
0 голосов
/ 19 января 2019

Я использовал этот запрос в SQL Server:

SELECT TOP 8
    DATE_FORMAT(s.created, "%Y-%m-%d") as "Date",
    count(s.id) AS "Accounts credited",
    sum(s.withdrawal) "Total Credited",
    100 * (sum(s.withdrawal) - sum(s1.withdrawal)) / sum(s1.withdrawal) "Difference in %"
FROM statements s
    LEFT JOIN statements s1 ON s1.created = s.created - 7
    AND (s1.status_id = 'OPEN' OR s1.status_id = 'PENDING')
WHERE (s.status_id = 'OPEN' OR  s.status_id = 'PENDING')
GROUP BY YEAR(s.created), MONTH(s.created), DAY(s.created)
ORDER BY s.created DESC

Вы просто обрабатываете ноль или ноль s1.withdrawal.

Я хочу, чтобы это сработало.

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