2017-10-05 27 views
0

我(想)我有一個有趣的窗口場景,與網站股票可用性跟蹤有關,通過標準SQL進行處理。這是試圖建立了基於該推,從股票的「手頭」數量爲某個特定產品BigQuery - 窗口化股票分類

事件我們有與此相關的問題3種事件類型時股票頭寸的看法:

StocklevelUpdated(PUSH):在每天晚上的午夜,我們會針對倉庫中給定產品的onHandQty可用性級別進行新的更新。如果每個產品的onHandQty數量作爲下一個交易日的新值,這基本上是一個很難'重置'。 (注意:即使沒有變化,這實際上每晚都會發送一條記錄)。

OrderAccepted(PULL):那一天的過程中,也有產品,在這種情況下對股票負值許多「OrderAccepted」事件「onHandQtyDelta」(現在還不到賣)。 -2訂購了2件產品。

OrderCancelled:可以有,以及對產品的數量cancelleations,這對「onHandQtyDelta」一個積極的價值,因爲它添加回可用庫存銷售)

下面是一個tabluar按照的時間順序查看一個稍微簡化版本的數據(注意:這顯示單個產品當然有很多)。

enter image description here

onHandQtyDelta - 換到onHandQty作爲本次活動

onHandQty的結果 - 這是在這一點上的淨正及時增量影響。

現在雖然上圖中顯示的所有值很好ledgering出來(雖然,注意29是這些午夜復位之一),在現實中,並非所有的數據可用,需要導出的一個值這些訂單事件類型中的每一個。即1丟失。

onHandQty:實際數據集中具有絕對值onHandQty的唯一行是「StocklevelUpdated」事件。實際上,這會在午夜(例如29)「重置」產品的這個值。日記需要基本追​​溯到最近的這些。但是,onHandQtyDelta需要派生。

onHandQtyDelta只有OrderAccepts和OrderCancelled事件具有需要用來計算onHandQty的這個值。

所以圖片講千言萬語,所以數據的真實性與看起來像下面的工作:

enter image description here

如何有效地做到這一點(因爲有上百萬行的10秒)做這個?

我的想法是使用窗口和'lag'函數來回顧以前的記錄onHandQty的值,看看它是什麼,然後做加法或減法來得到新的onHandQty值。

問題是,然後是一個遞歸問題,因爲前一個事件本身需要回顧它以前的等等....直到你到一個stocklevelUpdated事件,因爲這是唯一的事件具有實際值然後從中前進。但是,當你不知道還有多遠才能獲得這樣的事件時,如何使用窗口來做到這一點 - 可以是之間的任何數量的OrderAccepts和Cancells(或沒有!)

也許聰明的數組,產品行放入數組並執行一些數組agg函數?

我認爲Ive得到stuckon思維的窗口是這樣的,也許由一個簡單的解決方案蒙上陰影!對不起,所有的細節,但不想模糊我需要幫助。

列出了啓動測試數據集工作過(我剛剛整理它的產品和時間用於創建圖像的目的)

WITH stock_changes AS (
SELECT 
    "StocklevelUpdated" AS eventName, 
    Timestamp("2017-06-29T23:59:59") AS stockLevelEventAt, 
    "PRODUCT_190035001612" AS productId, 
    null AS onHandQtyDelta, 
    23 AS onHandQty 
UNION ALL (
SELECT 
    "StocklevelUpdated" AS eventName, 
    Timestamp("2017-06-29T23:59:59") AS stockLevelEventAt, 
    "PRODUCT_4545423454545" AS productId, 
    null AS onHandQtyDelta, 
    120 AS onHandQty) 
UNION ALL (
    SELECT 
    "OrderAccepted" AS eventName, 
    Timestamp("2017-06-30T01:02:20") AS stockLevelEventAt, 
    "PRODUCT_190035001612" AS productId, 
    -2 AS onHandQtyDelta, 
    null AS onHandQty) 
UNION ALL (
    SELECT 
    "OrderAccepted" AS eventName, 
    Timestamp("2017-06-30T02:19:20") AS stockLevelEventAt, 
    "PRODUCT_190035001612" AS productId, 
    -3 AS onHandQtyDelta, 
    null AS onHandQty) 
UNION ALL (
    SELECT 
    "OrderAccepted" AS eventName, 
    Timestamp("2017-06-30T05:13:20") AS stockLevelEventAt, 
    "PRODUCT_4545423454545" AS productId, 
    -3 AS onHandQtyDelta, 
    null AS onHandQty) 
UNION ALL (
    SELECT 
    "OrderCancelled" AS eventName, 
    Timestamp("2017-06-30T13:02:20") AS stockLevelEventAt, 
    "PRODUCT_190035001612" AS productId, 
    +2 AS onHandQtyDelta, 
    null AS onHandQty) 
UNION ALL (
    SELECT 
    "OrderCancelled" AS eventName, 
    Timestamp("2017-06-30T11:02:20") AS stockLevelEventAt, 
    "PRODUCT_4545423454545" AS productId, 
    2 AS onHandQtyDelta, 
    null AS onHandQty) 
UNION ALL (
SELECT 
    "StocklevelUpdated" AS eventName, 
    Timestamp("2017-06-30T23:59:59") AS stockLevelEventAt, 
    "PRODUCT_190035001612" AS productId, 
    null AS onHandQtyDelta, 
    29 AS onHandQty) 
UNION ALL (
SELECT 
    "StocklevelUpdated" AS eventName, 
    Timestamp("2017-06-30T23:59:59") AS stockLevelEventAt, 
    "PRODUCT_4545423454545" AS productId, 
    null AS onHandQtyDelta, 
    140 AS onHandQty) 
) 
SELECT * 
FROM stock_changes 
order by productId, stockLevelEventAt ASC 

回答

1

下面是BigQuery的標準SQL

#standardSQL 
WITH stock_changes AS (
    SELECT "StocklevelUpdated" AS eventName, TIMESTAMP("2017-06-29T23:59:59") AS stockLevelEventAt, 
    "PRODUCT_190035001612" AS productId, NULL AS onHandQtyDelta, 23 AS onHandQty UNION ALL 
    SELECT "StocklevelUpdated", TIMESTAMP("2017-06-29T23:59:59"),"PRODUCT_4545423454545",NULL, 120 UNION ALL 
    SELECT "OrderAccepted", TIMESTAMP("2017-06-30T01:02:20"),"PRODUCT_190035001612",-2, NULL UNION ALL 
    SELECT "OrderAccepted", TIMESTAMP("2017-06-30T02:19:20"),"PRODUCT_190035001612",-3, NULL UNION ALL 
    SELECT "OrderAccepted", TIMESTAMP("2017-06-30T05:13:20"),"PRODUCT_4545423454545",-3, NULL UNION ALL 
    SELECT "OrderCancelled", TIMESTAMP("2017-06-30T13:02:20"),"PRODUCT_190035001612",+2, NULL UNION ALL 
    SELECT "OrderCancelled", TIMESTAMP("2017-06-30T11:02:20"),"PRODUCT_4545423454545",2, NULL UNION ALL 
    SELECT "StocklevelUpdated", TIMESTAMP("2017-06-30T23:59:59"),"PRODUCT_190035001612",NULL, 29 UNION ALL 
    SELECT "StocklevelUpdated", TIMESTAMP("2017-06-30T23:59:59"),"PRODUCT_4545423454545",NULL, 140 
) 
SELECT 
    eventName, stockLevelEventAt, productId, 
    delta AS onHandQtyDelta, IFNULL(onHandQty, onHand) AS onHandQty 
FROM (
    SELECT *, 
    SUM(IFNULL(onHandQty,0) - delta) 
     OVER(PARTITION BY productId, format_timestamp('%Y-%m-%d', stockLevelEventAt) 
     ORDER BY stockLevelEventAt DESC 
     rows BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AS onHand 
    FROM (
    SELECT eventName, stockLevelEventAt, productId, onHandQty, 
     CASE 
     WHEN prev IS NULL THEN IFNULL(onHandQtyDelta, 0) 
     ELSE onHandQty - prev - delta 
     END AS delta 
    FROM (
     SELECT *, 
     SUM(IFNULL(onHandQtyDelta,0)) OVER(PARTITION BY productId, format_timestamp('%Y-%m-%d', stockLevelEventAt) ORDER BY stockLevelEventAt) AS delta, 
     LAG(onHandQty) OVER(PARTITION BY productId, eventName ORDER BY stockLevelEventAt) AS prev 
     FROM stock_changes 
    ) 
) 
) 
ORDER BY productId, stockLevelEventAt ASC 

結果如下

Row eventName   stockLevelEventAt  productId onHandQtyDelta onHandQty  
1 StocklevelUpdated 2017-06-29 23:59:59 UTC PRODUCT_190035001612 0 23 
2 OrderAccepted  2017-06-30 01:02:20 UTC PRODUCT_190035001612 -2 21 
3 OrderAccepted  2017-06-30 02:19:20 UTC PRODUCT_190035001612 -3 18 
4 OrderCancelled  2017-06-30 13:02:20 UTC PRODUCT_190035001612 2 20 
5 StocklevelUpdated 2017-06-30 23:59:59 UTC PRODUCT_190035001612 9 29 
6 StocklevelUpdated 2017-06-29 23:59:59 UTC PRODUCT_4545423454545 0 120 
7 OrderAccepted  2017-06-30 05:13:20 UTC PRODUCT_4545423454545 -3 117 
8 OrderCancelled  2017-06-30 11:02:20 UTC PRODUCT_4545423454545 2 119 
9 StocklevelUpdated 2017-06-30 23:59:59 UTC PRODUCT_4545423454545 21 140 

最有可能可以進一步優化 - 但我更注重獲得邏輯來實現,減少對優化

+0

米哈伊爾·哇感謝, - 病患者需要坐下來消化它現在有點大加讚賞。首先獲得正確的結果顯然是一個很好的開始,然後可以優化大約1200萬行這將是。 –

+0

當然。順便說一句,這個查詢有很好的機會來擴展你的真實數據與數百萬行 - 這取決於你的productID/days/etc。分配。你只是嘗試:o)並且不要忘記接受和投票,如果你會找到合適的 –

+0

很酷知道!只需查看完整數據集的SQL即可。如果有另一列「位置」(2個價值觀,「英國」或「美國」),其中實際上的productId +位置是獨一無二的,而並非只是productId參數(即相同的productId,不同的位置),這將如何變化?我認爲我已經通過將位置添加到分區和順序中來解決問題,但只是想檢查一下?此外,有時我們吹噓,所以onHandQty可以去負(以前是0,那麼我們有一個orderCreated,它爲負則)......目前,它顯示爲「零」。太好了,謝謝! –