Вычислить общую сумму в 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 |

это возможно?

7 52

7 ответов:

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

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 (running total). Не пропустите оператор SET вверху, чтобы сначала инициализировать текущую общую переменную, или вы просто получите столбец нулевых значений.

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, вы будете в порядке.

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

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

начиная с 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

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

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

  • сделать это за пределами MySql или
  • Использовать MySQL 5 Курсоры