2016-12-29 50 views
0

因此而艰难。我在PHP中回应了这些数据,但我认为在MySQL中进行查询会更好。减去前一行的数量MySQL

这里是我的表:

enter image description here

我的查询(错误):

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' 

仅检索两行,而sold_qty是错误的。

enter image description here

我想实现是这样的结果:

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

谁能帮助?

回答

1

你也可以使用这个没有JOIN表:出SELECT只是隐藏一些列。

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; 

样品

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> 
+0

真的很感谢代码。我正在通过每一部分工作,所以我可以完全理解它。在我的桌子上做一些测试我相信'GREATEST()'函数会有问题。这就是我的意思:https://s27.postimg.org/46h2hwstf/image.png'sold_qty'最后一行需要用'-7'来反映新来的库存和退货。想知道你的想法是修改这个以支持负数。 – bbruman

1

一个选项将使用相关的子查询。对于大集合来说,这当然不是最有效的方法,但对于返回的有限数量的行来说,这是可行的。

似乎有一个序列需要处理和返回行,但没有ORDER BY子句。从示例数据看来,它看起来像是timestamp列升序,Quantity列降序和/或id升序。我们只是猜测。

假设序列是timestampid,并假设(timestamp,id)元组是唯一的......这些都是相当合理的假设,但他们都只是假设,以及相当大的...

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 ... 

对于以足够的性能最好的射手,我们希望可用于相关子查询覆盖索引,作为一个合适的索引的例子:

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

如果应将行视为按(timestamp,id)以外的顺序排序,则需要修改ORDER BY和子查询中WHERE子句中的条件。


这只是一种可能的方法。还有其他查询模式会返回相同的结果。

+0

你的假设是正确的,感谢您的信息!有趣的方法。唯一的问题是它的返回负值,'0'' -25''-5''''',但是效果很好:) – bbruman

+0

@bbruman:Doh!我的错。负值是因为表达式正在做倒数减法......做'b-a'而不是'a-b' ...我编辑了答案来解决这个问题。 – spencer7593