简体   繁体   中英

Subtract Quantity From Previous Row MySQL

Having a tough time with this. I'm echo'ing this data out in PHP but I figured it would be better to make a query in MySQL.

Here's my table:

在此处输入图片说明

My Query (wrong):

SELECT i1.Quantity,
i1.timestamp,
(i2.Quantity - i1.Quantity) as sold_qty 
FROM InventoryTest_history i1
INNER JOIN
InventoryTest_history i2 ON i2.id = i1.id + 1
WHERE i1.SKU = '(L) U-Joint'

Is only retrieving two rows, and the sold_qty is wrong.

在此处输入图片说明

The result I am trying to achieve would look like this:

Quantity |  timestamp   | sold_qty
985         2016-12-27      0  
960         2016-12-28      25
955         2016-12-29      5

Can anyone help?

One option would be use a correlated subquery. This certainly isn't the most efficient approach for large sets, but for a limited number of rows being returned, it's workable.

There appears to be a sequence you want the rows processed and returned, but there is no ORDER BY clause. From the example data, it looks like it's either ascending by timestamp column, descending by Quantity column, and/or ascending by id . We're just guessing.

Assuming the sequence is by timestamp and id , and assuming that the (timestamp,id) tuple is unique... those are fairly reasonable assumptions, but they are just assumptions, and pretty big ones...

SELECT ih.Quantity
     , ih.timestamp

     , IFNULL(
                 ( SELECT pr.Quantity
                     FROM InventoryTest_history pr
                    WHERE pr.SKU = ih.SKU
                      AND pr.timestamp <= ih.timestamp
                      AND (pr.timestamp < ih.timestamp OR pr.id < ih.id )
                    ORDER BY pr.SKU DESC, pr.timestamp DESC, pr.id DESC
                    LIMIT 1
                 )
                 - ih.Quantity
       ,0) AS sold_qty

  FROM InventoryTest_history ih
 WHERE ih.SKU = '(L) U-Joint'
 ORDER BY ... 

For the best shot at adequate performance, we would want a covering index available for the correlated subquery, as an example of a suitable index:

 ... ON InventoryTest_history (SKU, timestamp, id, quantity) 

If the rows should be considered sequenced in an order other than by (timestamp,id) , the ORDER BY and the conditions in the WHERE clause of the subquery need to be modified.


This is just one possible approach. There are other query patterns that will return an equivalent result.

you can also use this without JOIN the table: the out SELECT is only to hide some columns.

SELECT Quantity, `timestamp`, sold_qty
FROM (
    SELECT i.*,
    @sold_qty := GREATEST(@last_qty - i.`Quantity`,0) as sold_qty,
    @last_qty := i.`Quantity` as last_qty
    FROM InventoryTest_history i
    CROSS JOIN ( SELECT @last_qty := '', @sold_qty := 0) as init
    ORDER BY `timestamp`
    ) as result;

sample

mysql> SELECT * from InventoryTest_history;

+----+-------------+----------+---------------------+
| id | SKU         | Quantity | timestamp           |
+----+-------------+----------+---------------------+
|  1 | (L) U-Joint |      985 | 2016-12-27 10:08:58 |
|  2 | (L) U-Joint |      960 | 2016-12-28 10:09:52 |
|  3 | (L) U-Joint |      955 | 2016-12-29 16:01:02 |
+----+-------------+----------+---------------------+
3 rows in set (0,02 sec)

mysql> SELECT Quantity, `timestamp`, sold_qty
    -> FROM (
    ->     SELECT i.*,
    ->     @sold_qty := GREATEST(@last_qty - i.`Quantity`,0) as sold_qty,
    ->     @last_qty := i.`Quantity` as last_qty
    ->     FROM InventoryTest_history i
    ->     CROSS JOIN ( SELECT @last_qty := '', @sold_qty := 0) as init
    ->     ORDER BY `timestamp`
    ->     ) as result;
+----------+---------------------+----------+
| Quantity | timestamp           | sold_qty |
+----------+---------------------+----------+
|      985 | 2016-12-27 10:08:58 |        0 |
|      960 | 2016-12-28 10:09:52 |       25 |
|      955 | 2016-12-29 16:01:02 |        5 |
+----------+---------------------+----------+
3 rows in set (0,00 sec)

mysql> SELECT i.*,
    -> @sold_qty := GREATEST(@last_qty - i.`Quantity`,0) as sold_qty,
    -> @last_qty := i.`Quantity` as last_qty
    -> FROM InventoryTest_history i
    -> CROSS JOIN ( SELECT @last_qty := '', @sold_qty := 0) as init
    -> ORDER BY `timestamp`;
+----+-------------+----------+---------------------+----------+----------+
| id | SKU         | Quantity | timestamp           | sold_qty | last_qty |
+----+-------------+----------+---------------------+----------+----------+
|  1 | (L) U-Joint |      985 | 2016-12-27 10:08:58 |        0 |      985 |
|  2 | (L) U-Joint |      960 | 2016-12-28 10:09:52 |       25 |      960 |
|  3 | (L) U-Joint |      955 | 2016-12-29 16:01:02 |        5 |      955 |
+----+-------------+----------+---------------------+----------+----------+
3 rows in set (0,00 sec)

mysql>

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