Для версий MySQL до 8.0 мы могли бы использовать пользовательские переменные, как показано в запросе OP.
Несколько замечаний:
Похоже, мы начали с простым GROUP BY created_date, group_uuid
запросом к таблице users
, чтобы получить ненулевые значения. Но там есть пропущенные строки, где в противном случае было бы нулевое число.
Так что, похоже, нам нужен источник календаря (отдельный список дат в данном диапазоне, запрос OP использует запрос таблицы аудита как источник календаря), и нам нужно это перекрестное соединение (декартово произведение) к отдельному списку значений uuid из группы вместе с именем. Для этого упражнения мы будем предполагать, что uuid
является уникальным в таблице groups
, и что каждое значение uuid
связано с отдельным значением name
. (Если это не так, нам нужно внести некоторые коррективы.)
Чтобы получить промежуточную сумму отдельно по группам, нам нужно обработать строки в групповом порядке, а затем в каждой группе по возрастанию. приказ. Когда мы обрабатываем строки, нам нужно сбросить промежуточный итог до нуля, когда мы начинаем новую группу, т.е. когда обнаруживаем изменение в значении uuid группы.
ПРИМЕЧАНИЕ. Справочное руководство MySQL дает специфические значения c предупреждение об использовании пользовательских переменных, как чтение, так и изменение в одном выражении, порядок операций не гарантируется. Вплоть до MySQL 5.7 с тщательно обработанными запросами мы наблюдаем предсказуемое поведение в порядке операций.
Итак, мы могли бы сделать что-то вроде этого:
SELECT q.date AS `Date`
, q.running_total AS `Cumulative`
, q.uptake AS `Uptake`
, q.name AS `Group`
FROM ( SELECT @rtot := IF(@prev_uuid = grp.uuid,@rtot,0) + IFNULL(cnt.uptake,0) AS `running_total`
, IFNULL(cnt.uptake,0) AS `uptake`
, @prev_uuid := grp.uuid AS `uuid`
, grp.name AS `name`
, cal.date AS `date`
FROM ( -- initialize user-defined variables
SELECT @prev_uuid := NULL
, @rtot := 0
) i
CROSS
JOIN ( -- calendar source for distinct date values
SELECT DATE(a.created_at) AS `date`
FROM `audit` a
WHERE a.created_at >= '2019-07-03'
AND a.created_at <= DATE(NOW())
GROUP BY DATE(a.created_at)
ORDER BY DATE(a.created_at)
) cal
CROSS
JOIN ( -- distinct list of group uuid we want to return
SELECT g.uuid AS `uuid`
, MAX(g.name) AS `name`
FROM `groups` g
WHERE g.name IN ('CompanyA','CompanyB')
GROUP BY g.uuid
) grp
LEFT
JOIN ( -- count by group and date
SELECT u.group_uuid AS `group_uuid`
, DATE(u.created_at) AS `date`
, COUNT(u.id) AS `uptake`
FROM `users` u
WHERE u.created_at >= '2019-07-03'
GROUP
BY u.group_uuid
, DATE(u.created_at)
) cnt
ON grp.uuid = cnt.group_uuid
AND cal.date = cnt.date
ORDER
BY grp.uuid
, cal.date
) q
ORDER
BY q.date DESC
, q.name ASC
Примечание: мы должны быть осторожны с порядком операций в списке SELECT, который использует переменные, определенные пользователем, например нам нужно проверить значение @prev_uuid (сохраненное из предыдущей строки) перед тем, как перезаписать его значением текущей строки.
Кроме того, это не проверяется, возможны синтаксические ошибки, пропущены парены. Я настоятельно рекомендую тестировать каждый из запросов встроенного представления отдельно (cal
, grp
, cnt
), чтобы убедиться, что ожидаемые результаты выполняются. (Предложение WHERE в запросе grp
запрещает возвращать, корректировать или удалять группы по мере необходимости.)
Затем мы можем перейти к тестированию следующего внешнего запроса q
и подтвердить результаты из что перед переносом q
в последнем самом внешнем запросе для переупорядочения строк и отображения столбцов в нужном порядке.
** FOLLOWUP **
, чтобы увидеть, можем ли мы получить MySQL чтобы соблюдать ORDER BY uuid
, мы можем изменить / заменить q
Изменить с этого:
SELECT q.date AS `Date`
, q.running_total AS `Cumulative`
, q.uptake AS `Uptake`
, q.name AS `Group`
FROM ( SELECT @rtot := IF(@prev_uuid = grp.uuid,@rtot,0) + IFNULL(cnt.uptake,0) AS `running_total`
, IFNULL(cnt.uptake,0) AS `uptake`
, @prev_uuid := grp.uuid AS `uuid`
, grp.name AS `name`
, cal.date AS `date`
FROM
...
ORDER
BY grp.uuid
, cal.date
) q
ORDER
BY q.date DESC
, q.name ASC
на
SELECT r.date AS `Date`
, r.running_total AS `Cumulative`
, r.uptake AS `Uptake`
, r.name AS `Group`
FROM ( SELECT @rtot := IF(@prev_uuid = q.uuid,@rtot,0) + q.uptake AS `running_total`
, q.uptake AS `uptake`
, @prev_uuid := q.uuid AS `uuid`
, q.name AS `name`
, q.date AS `date`
FROM ( SELECT grp.uuid AS `uuid`
, grp.name AS `name`
, cal.date AS `date`
, IFNULL(cnt.uptake,0) AS `uptake`
FROM
...
ORDER
BY grp.uuid
, cal.date
) q
ORDER
BY q.uuid
, q.date
) r
ORDER
BY r.date DESC
, r.name ASC