我有一个表,每行包含名为id(key),date,sign,value。
的字段Sign = 0是复位条件。它将用于设置初始累积值
Sign = +1是添加条件。它会将值与累计总和相加。
Sign = -1是一个减法,正如你猜的那样,它会减少累计总数。
顺序很重要,因此必须使用0,1,-1排序进行评估。
假设我想获得该值的累计和。
SELECT my_date, my_sign, my_value, @cum AS cum_before,
(@cum := IF( my_sign !=0, @cum + my_sign * my_value, my_value ) ) AS cum_after
FROM my_table, (SELECT @cum :=0) as t WHERE my_date LIKE '2016-05-%'
ORDER BY my_date, my_sign + ( my_sign =0 ) *2 DESC;
将正确显示:
my_date my_sign my_value cum_before cum_after
2016-05-02 0 10000.00 0 10000.00
2016-05-02 1 1860.00 10000 11860.00
2016-05-02 -1 1860.00 11860 10000.00
2016-05-03 1 1780.00 10000 11780.00
2016-05-06 1 4625.00 11780 16405.00
2016-05-09 1 14200.00 16405 30605.00
现在我想按周(或月)对其进行分组,并在处理组中的行之前将cum_before设置为初始值(顺便提一下应该是前一组的cum_after),并且cum_after作为累积处理组中的行后的值。 事情变得复杂,因为之前的状态变量@cum似乎是用组集的第一个值初始化的。
我正在创建一个临时表以保持正确的顺序,因为GROUP似乎不遵守任何ORDER BY子句(我猜它是在DB中出现的行)。
CREATE TEMPORARY TABLE _t_ SELECT id FROM my_table
ORDER BY my_date, my_sign + ( my_sign =0 ) *2 DESC ;
我在SUM函数中使用assign in(@cum:= value),在分组时相应地改变@cum,并将其乘以0而不干扰实数和,这将总和符号*值正常情况下,当找到重置条件时,将减去@cum并添加值字段。
SELECT min( my_date ) AS MinDate, max( my_date ) AS MaxDate,
@cum AS cum_before, SUM(
0 * ( @cum := IF( my_sign !=0, my_sign * my_value, my_value ) ) +
IF( my_sign !=0, my_sign * my_value, - @cum + my_value )
) AS cum_after
FROM my_table as F, _t_, (SELECT @cum :=0) AS t
WHERE _t_.id = F.id AND my_date LIKE '2016-05-%'
GROUP BY date_format( my_date, "%y%U" );
将提供以下内容:
MinDate MaxDate cum_before cum_after
2016-05-02 2016-05-06 10000 16405.00
2016-05-09 2016-05-09 14200 14200.00
这是错误的,因为我期望获得的是:
MinDate MaxDate cum_before cum_after
2016-05-02 2016-05-06 0 16405.00
2016-05-09 2016-05-09 16405 30605.00
基本上它似乎将@cum分配给集合中的第一行,而不是保留先前的变量值。
如果可能,我如何获得正确的分组?
答案 0 :(得分:0)
previous answer改编Haleemur Ali 它似乎无法在一个步骤中完成,因为在每个组之后重置累积变量。 因此,可能的解决方案如下:
SELECT MinDate, MaxDate, @cum as cum_before, (@cum:=@cum+tmp_cum) as cum_after
FROM ( SELECT min( my_date ) AS MinDate, max( my_date ) AS MaxDate,
SUM(
0 * ( @tmp := IF( my_sign !=0, my_sign * my_value, my_value ) ) +
IF( my_sign !=0, my_sign * my_value, - @tmp + my_value )
) AS tmp_cum
FROM my_table as F, _t_, (SELECT @tmp :=0) AS t
WHERE _t_.id = F.id AND my_date LIKE '2016-05-%'
GROUP BY date_format( my_date, "%y%U" ) ) as SUBQ, (SELECT @cum:=0) as tmp_var;
不了解性能,或者是否可以优化。