如何获得MySQL中连续行之间的区别?

时间:2019-08-22 16:57:10

标签: mysql

I have a table in mysql database this data.

id     date         number   qty
114    07-10-2018    200      5   
120    01-12-2018    300      10
123    03-02-2019    700      12
1126   07-03-2019    1000     15

I want to calculate difference between two consecutive rows and i need output format be like:

id     date         number  diff    qty    avg
114    07-10-2018    200     0       5      0
120    01-12-2018    300     100     10     10
123    03-02-2019    700     400     12     33.33
1126   07-03-2019    1000    300     15     20
  

有人知道如何在mysql查询中执行此操作吗?我希望diff和avg列的第一个值为0,其余为差异。

2 个答案:

答案 0 :(得分:5)

对于 MySQL 8 ,然后使用Lag窗口功能。

19/08/22 21:26:06 ERROR Executor: Exception in task 3.0 in stage 0.0 (TID 3)
com.amazonaws.services.kinesisfirehose.model.AmazonKinesisFirehoseException: 1 validation error detected: Value '[]' at 'records' failed to satisfy constraint: Member must have length greater than or equal to 1 (Service: AmazonKinesisFirehose; Status Code: 400; Error Code: ValidationException; Request ID: c91aea46-66de-013c-9cc3-e0e862cbc37c)
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleErrorResponse(AmazonHttpClient.java:1695)
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeOneRequest(AmazonHttpClient.java:1350)
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:1101)
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:758)
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:732)
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:714)
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:674)
        at com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:656)
        at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:520)
        at com.amazonaws.services.kinesisfirehose.AmazonKinesisFirehoseClient.doInvoke(AmazonKinesisFirehoseClient.java:1179)
        at com.amazonaws.services.kinesisfirehose.AmazonKinesisFirehoseClient.invoke(AmazonKinesisFirehoseClient.java:1148)
        at com.amazonaws.services.kinesisfirehose.AmazonKinesisFirehoseClient.invoke(AmazonKinesisFirehoseClient.java:1137)
        at com.amazonaws.services.kinesisfirehose.AmazonKinesisFirehoseClient.executePutRecordBatch(AmazonKinesisFirehoseClient.java:871)
        at com.amazonaws.services.kinesisfirehose.AmazonKinesisFirehoseClient.putRecordBatch(AmazonKinesisFirehoseClient.java:842)
        at com.siriusxm.kafka_kinesis.KafkaKinesisStructureStreamingBatch$1.close(KafkaKinesisStructureStreamingBatch.java:118)
        at org.apache.spark.sql.execution.streaming.ForeachSink$$anonfun$addBatch$1.apply(ForeachSink.scala:60)
        at org.apache.spark.sql.execution.streaming.ForeachSink$$anonfun$addBatch$1.apply(ForeachSink.scala:49)
        at org.apache.spark.rdd.RDD$$anonfun$foreachPartition$1$$anonfun$apply$29.apply(RDD.scala:935)
        at org.apache.spark.rdd.RDD$$anonfun$foreachPartition$1$$anonfun$apply$29.apply(RDD.scala:935)
        at org.apache.spark.SparkContext$$anonfun$runJob$5.apply(SparkContext.scala:2074)
        at org.apache.spark.SparkContext$$anonfun$runJob$5.apply(SparkContext.scala:2074)
        at org.apache.spark.scheduler.ResultTask.runTask(ResultTask.scala:87)
        at org.apache.spark.scheduler.Task.run(Task.scala:109)
        at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:345)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

对于MySQL 5.7或更低版​​本

我们可以使用MySQL variable来完成这项工作。考虑您的表名是“ test”。

   if (isset($_POST['signin'])) {

    $uname=$_POST['username'];
    $password=md5($_POST['password']);

    $sql ="SELECT * FROM users WHERE username=:uname and Password=:password";
    $run_guest= $dbh -> prepare($sql);
    $query-> bindParam(':uname', $uname, PDO::PARAM_STR);
    $query-> bindParam(':password', $password, PDO::PARAM_STR);
    $query-> execute();
    $results=$query->fetchAll(PDO::FETCH_OBJ);
    if($query->rowCount() > 0)
    {
        foreach ($results as $result) {
            $status=$result->Status;
            $role = $result->Role;
            $_SESSION['uid']=$result->id;
        }
        if($status==0)
        {
            $msg="Your account is Inactive. Please contact admin";
        }
        if($role='Guest'){
            $_SESSION['gtlogin']=$_POST['username'];
            echo "<script type='text/javascript'> document.location = 'changepassword.php'; </script>";
        }
        if($role='Staff'){
            $_SESSION['stlogin']=$_POST['username'];
            echo "<script type='text/javascript'> document.location = 'staff/dashboard.php'; </script>";
        }
        if($role='Admin'){
            $_SESSION['alogin']=$_POST['username'];
            echo "<script type='text/javascript'> document.location = 'admin/changepassword.php'; </script>";
        }
    }

    else{

        echo "<script>alert('Invalid Details');</script>";

    }

说明:

  • SELECT test.id, test.date, test.number, test.qty, IFNULL(test.number - LAG(test.number) OVER w, 0) AS diff, ROUND(IFNULL(test.number - LAG(test.number) OVER w, 0)/ test.qty, 2) AS 'Avg' FROM purchases test WINDOW w AS (ORDER BY test.`date` ASC); 我们在FROM子句中将变量 @prev_number 初始化为零,并与 test 表的每一行连接。
  • MySQL Query: SELECT test.id, test.date, test.number, test.qty, @diff:= IF(@prev_number = 0, 0, test.number - @prev_number) AS diff, ROUND(@diff / qty, 2) 'avg', @prev_number:= test.number as dummy FROM test, (SELECT @prev_number:= 0 AS num) AS b ORDER BY test.`date` ASC; ------------------------------------------------------------------------------- Output: | id | date | number| qty | diff | avg | dummy | ----------------------------------------------------------------- | 114 | 2018-10-07 | 200 | 5 | 0 | 0.00 | 200 | | 120 | 2018-12-01 | 300 | 10 | 100 | 10.00 | 300 | | 123 | 2019-02-03 | 700 | 12 | 400 | 33.33 | 700 | | 1126 | 2019-03-07 | 1000 | 15 | 300 | 20.00 | 1000 | 首先,我们生成差异,然后创建另一个变量 diff ,以将其重新用于平均计算。我们还加入了一个条件,以使第一行的差异为零。
  • (SELECT @prev_number:= 0 AS num) AS b,我们正在为此变量设置当前 number ,以便下一行可以使用。

注意:我们必须首先在“ 差异”和“ 平均值”中使用此变量,然后将其设置为新值,因此下一行可以访问上一行的值。

您可以根据需要跳过/修改order by子句。

答案 1 :(得分:1)

可能会有更好的方法,但是请尝试以下方法:

SELECT A.id,
       A.date,
       A.number,
       A.qty,
       A.diff,
       B.avg
FROM
(SELECT *, abs(LAG(number, 1, number) OVER (ORDER BY id) - number) AS 'diff'
FROM table) AS A
JOIN
(SELECT *, abs(LAG(number, 1, number) OVER (ORDER BY id) - number)/qty AS 'avg' FROM table) AS B
ON A.id = B.id;