简体   繁体   中英

How to write a query to get the sum of last n elements of each row?

I want to calculate sum of last N elements in a database table for each row, I tried various approaches but i can;t find any way to do this in a single query.

This is what I have, let's say N is 2, and I have this data,

day shop  sales
1    A    10
2    A    20  
3    A    30
4    A    40
5    A    50
1    B    100
2    B    200
3    B    300
4    B    400
5    B    500

I want the following result

day | shop | total sales of last 2 days
1     A       10
2     A       30 //sum of 10 and 20   
3     A       50 // sum of 20 and 30 
4     A       70  //sum of 30 and 40
5     A       90 // sum of 40 and 50
1     B       100
2     B       300
3     B       500
4     B       700
5     B       900

Is it even possible to do this in single query?

In MySQL 8+, just use lag() :

select t.*,
       (t.sales + lag(t.sales, 1, 0) over (partition by t.shop order by t.day)
       ) as two_day_sales
from t;

In older versions, use a left join :

select t.*,
       (t.sales + coalesce(tprev.sales, 0)) as two_day_sales
from t left join
     t tprev
     on tprev.shop = t.shop and
        tprev.day = t.day - 1;

May I suggest the following idea:

  • Get all the sales ordered by shop ASC, day ASC .
  • Then in your back-end language (I use PHP), write the code that gets the total sales according to numberOfDays in an array.

Here is the full example in PHP, but you can use any language that goes with MySQL as you like:

$connection = mysqli_connect("localhost", "root", "", "database_test");

$sql_query = "
                SELECT *
                FROM table_sales
                ORDER BY shop ASC, day ASC
             ";

$result = mysqli_query($connection, $sql_query);

$numberOfDays = 3;
$daily_sales = array();
$total_sales = array();
$i = 0;

while($row = mysqli_fetch_array($result)) {

    $daily_sales[$i] = $row;
    $total_sales[$i] = $row;
    $total_sales[$i]["sales"] = 0;

    $offset = $i - $numberOfDays + 1;

    if($offset < 0)
        $offset = 0;

    for($j = $offset; $j <= $i; $j++) {
        if($total_sales[$i]["shop"] == $daily_sales[$j]["shop"])
            $total_sales[$i]["sales"] += $daily_sales[$j]["sales"];
    }

    $i++;
}

mysqli_close($connection);

The $total_sales is a multi-dimensional array. You can access it like this for example: $total_sales[0]["sales"] and it will give you the total amount of the sales for a numberOfDays for a specific shop that you can see in $total_sales[0]["shop"] .

Remember to make error handling in the MySQLi functions otherwise if no result is returned the array will be empty.

If you any questions please comment, I'll gladly help you out.

EDIT: I don't think its possible to do what you were trying to achieve solely in MySQL, neither do I think one is supposed to. That is why I combined PHP with MySQL.

Also, depending on whether you might have many thousands of sales, it might not be a good idea to retrieve all the sales results in a massive query. As a solution you can retrieve them shop-specifically. The changes that have to be made to the code is that the SQL has to look like this:

SELECT *
FROM table_sales
WHERE shop = ?
ORDER BY day ASC

And then remove this line, as it becomes unnecessary:

if($total_sales[$i]["shop"] == $daily_sales[$j]["shop"])

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM