我有一个复杂的查询(包含多个联接,联合),该查询返回一组包含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。
谢谢。
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
更新
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