2016-12-29 78 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