mysql中一组行的累积和

p1iqtdky  于 2023-04-28  发布在  Mysql
关注(0)|答案(3)|浏览(106)

我有一个复杂的查询(包含多个连接、联合),它返回一组包含id、day、hr、amount的行。查询的输出如下所示:

id day    hr  amount 
1   1      1   10       
1   1      2   25       
1   1      3   30        
1   2      1   10       
1   2      2   40       
1   2      2   30        
2   1      1   10       
2   1      2   15        
2   1      3   30       
2   2      1   10       
2   2      2   20      
2   2      2   30

我需要找到每个id的累积总数,每天的每小时。输出应该是这样的:

id day    hr  amount cumulative total
1   1      1   10       10
1   1      2   25       35
1   1      3   30       65 
1   2      1   10       10
1   2      2   40       50
1   2      2   30       80 
2   1      1   10       10
2   1      2   15       25 
2   1      3   30       55
2   2      1   10       10
2   2      2   20       30
2   2      2   30       60

生成第一个输出的初始查询如下所示:

select id, day, hr, amount from
( //multiple joins on multiple tables)a
left join
(//unions on multiple tables)b
on a.id=b.id;

SQL查询是什么来获得第二个输出中描述的累积和的?不应在溶液中使用SET。
谢谢。

svmlkihl

svmlkihl1#

  • 更新 *

MySQL 8.0引入了“窗口函数”,功能等同于SQL Server“窗口函数”(由Transact-SQL OVER语法提供分区和排序)和Oracle“分析函数”。它现在还支持CTE。
12.第十二章21窗口功能https://dev.mysql.com/doc/refman/8.0/en/window-functions.html
这里提供的答案是针对MySQL 8之前版本的方法。0.

  • 原始答案 *

MySQL不提供类型分析函数,您可以使用它来获取运行的“累积和”,就像其他DBMS(如Oracle或SQL Server)中可用的分析函数一样。)
但是,可以使用MySQL模拟一些分析函数。
至少有两种可行的方法:
一种是使用相关子查询来获得小计。这种方法在大型集合上的开销可能很大,如果外部查询上的 predicate 很复杂,则会很复杂。这实际上取决于“多个表上的多个连接”有多复杂。(MySQL也不支持CTE。)
另一种方法是利用MySQL用户变量,进行一些控制中断处理。这里的“技巧”是对查询的结果进行排序(使用ORDER BY),然后将查询 Package 在另一个查询中。
我将给予一个后一种方法的例子。
由于MySQL执行操作的顺序,在将当前行的idday的值保存到用户变量中之前,需要计算cumulative_total列。把这一栏放在第一位是最简单的。
别名为i的内联视图(在下面的查询中)只是用来初始化用户变量,以防这些变量已经在会话中设置。如果已经为它们赋值,我们希望忽略它们的当前值,最简单的方法是初始化它们。
您的原始查询被 Package 在括号中,并在下面的示例中被赋予一个别名c。对原始查询的唯一更改是添加了ORDERBY子句,因此可以确保按顺序处理查询中的行。
外部选择检查当前行的idday值是否与前一行“匹配”。如果是,我们将当前行的amount添加到累计小计中。如果它们不匹配,那么我们将累计小计重置为零,并添加当前行的金额(或者更简单地说,只是分配当前行的金额)。
在我们完成了累积总数的计算之后,我们将当前行的idday值保存到用户变量中,以便在处理下一行时可以使用它们。
例如:

SELECT IF(@prev_id = c.id AND @prev_day = c.day
         ,@cumtotal := @cumtotal + c.amount
         ,@cumtotal := c.amount) AS cumulative_total
     , @prev_id  := c.id  AS `id`
     , @prev_day := c.day AS `day`
     , c.hr
     , c.amount AS `amount'
  FROM ( SELECT @prev_id  := NULL
              , @prev_day := NULL
              , @subtotal := 0
       ) i
  JOIN (

         select id, day, hr, amount from
         ( //multiple joins on multiple tables)a
         left join
         (//unions on multiple tables)b
         on a.id=b.id

         ORDER BY 1,2,3
       ) c

如果有必要以不同的顺序返回列,累积总计作为最后一列,那么一种选择是将整个语句 Package 在一组括号中,并将该查询用作内联视图:

SELECT d.id
     , d.day
     , d.hr
     , d.amount
     , d.cumulative_total
FROM (
       // query from above
     ) d
dxxyhpgq

dxxyhpgq2#

如果您使用的是MySQL 8或更高版本,则应该使用window functions。您的查询将为:

SELECT
  id, day, hr, amount,
  SUM (amount) OVER (PARTITION BY id, day ORDER BY hr) AS `cumulative total`
FROM t

其中t是您的表b左连接到a。一些注意事项:

  • PARTITION BY子句保证您获得每个idday的累计和,因此每天我们都重新开始求和
  • ORDER BY子句定义了累积的发生顺序
kkih6yb8

kkih6yb83#

给你,这是你最后的总数。..

select f1.id, f1.day, f1.hr, f1.amount, sum(f2.amount) as culminative_total from foo f1
 inner join foo f2 on (f1.day = f2.day and f1.id=f2.id)
 where f2.hr <= f1.hr
 group by f1.id, f1.day, f1.hour;

相关问题