计算MySQL中的运行总计

nic*_*ckf 56 mysql sql

我有这个MySQL查询:

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

返回的内容如下:

d  | COUNT(*) |
20 |  5       |
21 |  7       |
22 | 12       |
23 |  4       |
Run Code Online (Sandbox Code Playgroud)

我真正喜欢的是最后一列显示运行总数:

d  | COUNT(*) | ??? |
20 |  5       |   5 |
21 |  7       |  12 |
22 | 12       |  24 |
23 |  4       |  28 |
Run Code Online (Sandbox Code Playgroud)

这可能吗?

小智 107

也许是一个更简单的解决方案,可以防止数据库不得不进行大量查询.这只执行一个查询,然后在一次传递中对结果进行一些数学计算.

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
Run Code Online (Sandbox Code Playgroud)

这将为您提供额外的RT(运行总计)列.不要错过顶部的SET语句来初始化运行的总变量,否则您将获得一列NULL值.

  • 值得一提的是`@ rentot`变量可以在`FROM`子句中的`SELECT`语句中设置如下:`... AS q1,(SELECT @runtot:= 0)AS n`.这可能会让php人员的生活变得更加容易,因为现在你只有一个语句查询. (36认同)
  • 你工作太辛苦了.下次使用`WITH ROLLUP`. (5认同)
  • Ariel,请提供一个工作示例作为帖子的答案,而不是留下飞越.很想知道你的建议是如何运作的! (4认同)
  • 对于那些想使用PHP的基本MySQL函数执行类似操作的人,请确保单独运行第一行(但仍要在第二行之前)。 (2认同)

cdo*_*ner 10

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
Run Code Online (Sandbox Code Playgroud)

这将需要一些语法调整(我没有MySQL来测试它),但它向您展示了这个想法.子查询只需返回并添加已包含在外部查询中的所有新内容,并且必须为每一行执行此操作.

看一下这个问题,了解如何使用连接来完成相同的工作.

为了解决随着数据增长而导致性能下降的担忧:一年366天,我假设您没有多年运行此查询,子查询将被评估多达366次.使用适当的日期索引和hasPaid标志,你会没事的.


Luk*_*der 5

从 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
Run Code Online (Sandbox Code Playgroud)

在上面的查询中,聚合函数count(*)嵌套在 window function 内部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
Run Code Online (Sandbox Code Playgroud)