开发者社区 问答 正文

mysql中一组行的累计总和?mysql

我有一个复杂的查询(包含多个联接,联合),该查询返回一组包含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。

谢谢。

展开
收起
保持可爱mmm 2020-05-17 12:35:57 573 分享 版权
1 条回答
写回答
取消 提交回答
  • 更新

    MySQL 8.0引入了“窗口函数”,与SQL Server“窗口函数”等效的功能(具有通过Transact-SQL OVER语法提供的分区和排序)和Oracle“分析函数”。

    MySQL参考手册12.21窗口函数https://dev.mysql.com/doc/refman/8.0/en/window-functions.html

    此处提供的答案是针对8.0之前的MySQL版本的方法。

    原始答案

    MySQL不提供用于获取运行中的“累计和”的类型分析功能,例如其他DBMS(例如Oracle或SQL Server)中可用的分析功能。

    但是,可以使用MySQL模拟某些分析功能。

    有(至少)两种可行的方法:

    一种是使用相关的子查询来获取小计。这种方法在大型集合上可能很昂贵,并且如果外部查询的谓词很复杂,则可能很复杂。实际上,这取决于“多个表上的多个联接”的复杂程度。(不幸的是,MySQL也不支持CTE。)

    另一种方法是利用MySQL用户变量,进行一些控制中断处理。这里的“技巧”是对查询结果进行排序(使用ORDER BY),然后将查询包装在另一个查询中。

    我将举一个后一种方法的例子。

    由于MySQL执行操作的顺序,在将当前行中cumulative_total的值id和day当前行中的值保存到用户变量之前,需要计算该列。将本专栏放在第一位是最容易的。

    别名为i的内联视图(在下面的查询中)仅用于初始化用户变量,以防万一这些用户变量已在会话中设置。如果已经为它们分配了值,则我们想忽略它们的当前值,最简单的方法是初始化它们。

    c在下面的示例中,原始查询被括在括号中,并被赋予了别名。原始查询的唯一更改是添加了ORDER BY子句,因此我们可以确保我们按顺序处理查询中的行。

    外部选择检查当前行中的idand day值是否与上一行“匹配”。如果是这样,我们将amount当前行中的和添加到累计小计中。如果它们不匹配,则我们将累计小计重置为零,并添加当前行中的金额(或更简单地说,只需分配当前行中的金额)。

    完成累计总数的计算后,我们将当前行中的id和day值保存到用户变量中,以便在处理下一行时可用。

    例如:

    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
    

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

    SELECT d.id , d.day , d.hr , d.amount , d.cumulative_total FROM ( // query from above ) d来源:stack overflow

    2020-05-17 12:38:23
    赞同 展开评论