繁体   English   中英

计算 MySQL 中的运行总计

[英]Calculate a running total in 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 |

这可能吗?

也许对您来说是一个更简单的解决方案,并且可以防止数据库执行大量查询。 这仅执行一个查询,然后在一次通过中对结果进行一些数学运算。

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 值。

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 来测试它),但它向您展示了这个想法。 子查询只需返回 go 并将您已经包含在外部查询中的所有新鲜内容相加,并且它必须对每一行都执行此操作。

看看这个问题,了解如何使用连接来完成同样的任务。

为了解决随着数据增长而导致性能下降的问题:因为有最大值。 一年 366 天,并且我假设您没有针对多年运行此查询,子查询将被评估多达 366 次。 有了正确的日期索引和 hasPaid 标志,你会没事的。

从 MySQL 8 开始,您将使用window 函数进行此类查询:

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

In the above query, the aggregate function count(*) is nested inside of the window function sum(..) OVER (..) , which is possible because of the logical order of operations in 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

可以使用 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 服务器期间存在

上面的查询使用子查询,它返回临时表中所有行的余额,包括当前行。 余额分配到实际表中的当前行

除非您别无选择,只能在 sql 中执行此操作,否则我将使用进行查询的编程语言对结果求和。 随着表格的增长,这样的嵌套将变得非常缓慢。

您可以使用 Cross Join 语句或一些 slef 连接来破解它,但是对于任何大型数据集,它都会变慢,因此最好在后查询处理器中完成; 客户端代码中的 cursor

这是游标比基于集合的查询更快的唯一地方之一,如果性能至关重要,我会

  • 在 MySql 之外执行此操作或
  • 使用 MySql 5 个光标

我会说这是不可能的,每个结果行都应该是独立的。 使用编程语言获取这些值

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM