【问题标题】:getting the difference between two rows and perform mathematical operation on the difference mysql获取两行之间的差异并对差异mysql执行数学运算
【发布时间】:2017-01-28 22:24:21
【问题描述】:

例如,我的数据集如下所示

ID|Value
 1|10
 1|3
 2|9
 2|10
 2|15

我需要找到相同 ID 的两个连续元素之间的差异并存储该值,然后再次找到差异并将存储的值与具有相同 ID 的所有值的新差异相乘。这必须一直持续到存在具有相同 ID 的元素。 因此我的最终数据集应该看起来像

ID|Value
 1|-7
 2|5

有没有人有任何建议我应该如何使用 sql 来解决这个问题

【问题讨论】:

  • SQL 表代表 无序 集。因此,没有“两个连续的 [行]”之类的东西,除非您有一个指定排序的列。我没有看到这样的专栏。
  • id 2 的-5 来自哪里?
  • @Barmar 对不起它的 5
  • 如果您有另一列未显示指定排序,您可以使用用户定义的变量来保存前一行的值,然后减去当前行的值。从中获得价值。
  • @AbuKurian 为什么是10-9 而不是9-10?对于 ID 1,它是 10-3

标签: php mysql sql


【解决方案1】:

计算连续行之间的差异 -

MariaDB [sandbox]> SELECT T.*,
    -> IF(T.TID <> @P ,@RN:=1,@RN:=@RN+1) RN,
    -> IF(T.TID <> @P ,0, @PVAL) PVAL,
    -> IF(T.TID <> @P ,0, T.VALUE * 1.00 - @PVAL) DIFF,
    -> @P:=T.TID,
    -> @PVAL:=T.VALUE
    -> FROM(SELECT @RN:=0,@P:=0,@PVAL:=0.00,@DIFF:=0.00) RN,T
    -> ORDER BY T.TID,T.dt;
+------------+------+-------+------+------+------+-----------+----------------+
| dt         | TID  | Value | RN   | PVAL | DIFF | @P:=T.TID | @PVAL:=T.VALUE |
+------------+------+-------+------+------+------+-----------+----------------+
| 2017-01-01 |    1 |    10 |    1 | 0    |    0 |         1 |             10 |
| 2017-01-02 |    1 |     3 |    2 | 10   |   -7 |         1 |              3 |
| 2017-01-01 |    2 |     9 |    1 | 0    |    0 |         2 |              9 |
| 2017-01-02 |    2 |    10 |    2 | 9    |    1 |         2 |             10 |
| 2017-01-03 |    2 |    15 |    3 | 10   |    5 |         2 |             15 |
+------------+------+-------+------+------+------+-----------+----------------+
5 rows in set (0.00 sec)

但是 sql(据我所知的任何版本)中没有聚合函数可以计算差异的乘积(如果这是正确的话)。更重要的是,您似乎想为每个 tid 丢弃第一行。 您可以通过 group_concatenating 将差异合并到一个表中,然后调用一个存储过程来启动对动态 sql 的调用(顺便说一下,您不能在存储函数中使用动态 sql)。

这个存储过程

drop procedure if exists f;
delimiter //

CREATE DEFINER=`root`@`localhost` procedure `F`(
    instring varchar(200)
)

LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
begin
declare   tempstring varchar(100);
declare   outstring  varchar(100);
declare  tempid int;
declare  checkit int;
declare maxrecs int;
set checkit = 0;
set maxrecs = (select count(*) from temp);

looper: while   checkit < maxrecs do
select tid,calc into    tempid,tempstring from temp limit checkit,1; 
set checkit = checkit + 1;  
if instr(tempstring,',')  = 0 then 
    update temp
    set    rsult  = tempstring; 
else
    set outstring  = replace(tempstring,',','*');
    set outstring  = concat('update temp set rsult = (Select ',outstring,') where tid = ', tempid, ';');
    set @sqlstmt = outstring;
    #select checkit, maxrecs, outstring;
    prepare sqlstmt from @sqlstmt;  
    execute sqlstmt;
    deallocate prepare sqlstmt;
end if;

end while;
end //

delimiter ;

在此脚本中调用时会产生您想要的结果

*ariaDB [sandbox]> drop table if exists temp;
Query OK, 0 rows affected (0.09 sec)

MariaDB [sandbox]> create table temp as
    -> select s.tid,group_concat(s.diff) calc, 1.00 as rsult
    -> from
    -> (
    -> SELECT T.*,
    -> IF(T.TID <> @P ,@RN:=1,@RN:=@RN+1) RN,
    -> IF(T.TID <> @P ,0, @PVAL) PVAL,
    -> IF(T.TID <> @P ,0, T.VALUE * 1.00 - @PVAL) DIFF,
    -> @P:=T.TID,
    -> @PVAL:=T.VALUE
    -> FROM(SELECT @RN:=0,@P:=0,@PVAL:=0.00,@DIFF:=0.00) RN,T
    -> ORDER BY T.TID,T.dt
    -> ) s
    -> where s.rn <> 1
    -> group by s.tid;
Query OK, 2 rows affected (0.23 sec)
Records: 2  Duplicates: 0  Warnings: 0

MariaDB [sandbox]>
MariaDB [sandbox]>
MariaDB [sandbox]> call f('1');
Query OK, 0 rows affected (0.07 sec)

MariaDB [sandbox]>
MariaDB [sandbox]> select * from temp;
+------+-----------+-------+
| tid  | calc      | rsult |
+------+-----------+-------+
|    1 | -7.00     | -7.00 |
|    2 | 1.00,5.00 |  5.00 |
+------+-----------+-------+
2 rows in set (0.00 sec)*

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-08-22
    • 1970-01-01
    • 2016-08-26
    • 2020-09-12
    • 1970-01-01
    • 1970-01-01
    • 2014-05-04
    • 2022-12-09
    相关资源
    最近更新 更多