Подтвердить что ты не робот

Вычислить текущую сумму в MySQL

У меня есть этот запрос MySQL:

SELECT DAYOFYEAR(`date`)  AS d, COUNT(*) 
FROM  `orders` 
WHERE  `hasPaid` > 0
GROUP  BY d
ORDER  BY d

Что возвращает что-то вроде этого:

d  | COUNT(*) |
20 |  5       |
21 |  7       |
22 | 12       |
23 |  4       |

Мне бы очень хотелось, чтобы еще один столбец в конце отображал текущее количество:

d  | COUNT(*) | ??? |
20 |  5       |   5 |
21 |  7       |  12 |
22 | 12       |  24 |
23 |  4       |  28 |

Возможно ли это?

4b9b3361

Ответ 1

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

SET @runtot:=0;
SELECT
   q1.d,
   q1.c,
   (@runtot := @runtot + q1.c) AS rt
FROM
   (SELECT
       DAYOFYEAR(`date`) AS d,
       COUNT(*) AS c
    FROM  `orders`
    WHERE  `hasPaid` > 0
    GROUP  BY d
    ORDER  BY d) AS q1

Это даст вам дополнительный столбец RT (текущий общий). Не пропустите инструкцию SET сверху, чтобы сначала инициализировать текущую общую переменную, или вы получите столбец значений NULL.

Ответ 2

SELECT 
   DAYOFYEAR(O.`date`)  AS d, 
   COUNT(*),
   (select count(*) from `orders` 
       where  DAYOFYEAR(`date`) <= d and   `hasPaid` > 0)
FROM  
  `orders` as O
WHERE  
  O.`hasPaid` > 0
GROUP  BY d
ORDER  BY d

Для этого потребуется синтаксическая настройка (у меня нет MySQL для ее проверки), но она показывает вам эту идею. Подзапрос просто должен вернуться и добавить все свежее, что вы уже включили во внешний запрос, и это нужно сделать для каждой строки.

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

Чтобы решить проблемы ухудшения производительности с ростом данных: поскольку существует макс. 366 дней в году, и я предполагаю, что вы не выполняете этот запрос в течение нескольких лет, подзапрос будет оцениваться до 366 раз. При правильных индексах даты и флага hasPaid вы будете в порядке.

Ответ 3

Начиная с MySQL 8, вы будете использовать оконные функции для этого вида запроса:

SELECT dayofyear('date') AS d, count(*), sum(count(*)) OVER (ORDER BY dayofyear('date'))
FROM 'orders'
WHERE 'hasPaid' > 0
GROUP BY d
ORDER BY d

В приведенном выше запросе агрегатная функция count(*) вложена в оконную функцию sum(..) OVER (..), что возможно из-за логического порядка операций в SQL. Если это слишком запутанно, вы можете легко использовать производную таблицу или предложение WITH , чтобы лучше структурировать свой запрос:

WITH daily (d, c) AS (
  SELECT dayofyear('date') AS d, count(*)
  FROM 'orders'
  WHERE 'hasPaid' > 0
  GROUP BY d
)
SELECT d, c, sum(c) OVER (ORDER BY d)
ORDER BY d

Ответ 4

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

Ответ 5

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

Ответ 6

Вы можете взломать это, используя инструкцию Cross Join или некоторые соединения slaf, но она будет замедляться с любыми большими наборами данных, поэтому, вероятно, это лучше всего сделать в обработчике почтовых запросов; либо курсор кода клиента

Ответ 7

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

  • Сделайте это за пределами MySql или
  • Использование курсоров MySql 5

Ответ 8

Можно рассчитать текущий баланс, используя временную таблицу в MySQL. Следующий запрос должен работать:

CREATE TEMPORARY table orders_temp1 (SELECT id, DAYOFYEAR('date')  AS d, COUNT(*) as total FROM  'orders' WHERE  'hasPaid' > 0 GROUP BY d ORDER  BY d);
CREATE TEMPORARY table orders_temp2 (SELECT * FROM orders_temp1);
SELECT d, total, (SELECT SUM(t2.total) FROM orders_temp2 t2 WHERE t2.id<=t1.id) as running_total FROM orders_temp1 t1;

Временная таблица используется для организации запроса. Обратите внимание, что временная таблица существует только на время подключения к серверу MySQL.

Вышеупомянутый запрос использует подзапрос, который возвращает баланс всех строк во временной таблице до и включая текущую строку. Баланс присваивается текущей строке в фактической таблице