我有这个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值.
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标志,你会没事的.
从 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)