window以内的减法

Subtracting number within window

假设我有一个 table:

WITH MY_TABLE AS (SELECT 'Order1' ORDER_NUM, 1000 TO_PRODUCE, 'ProductID1' PRODUCT_ID, 1 RN, 3500 PRODUCED, 3500 WPRODUCED FROM DUAL 
                  UNION ALL
                  SELECT 'Order1' ORDER_NUM, 1000 TO_PRODUCE, 'ProductID1' PRODUCT_ID, 2 RN, 0 PRODUCED, 3500 WPRODUCED FROM DUAL 
                  UNION ALL
                  SELECT 'Order1' ORDER_NUM, 1000 TO_PRODUCE, 'ProductID1' PRODUCT_ID, 3 RN, 0 PRODUCED, 3500 WPRODUCED FROM DUAL)
SELECT * FROM MY_TABLE

我想根据TO_PRODUCE减去PRODUCED,剩下的留在最后一个RN(RowNumber) like

1000

1000

1500

我写了下面的查询,但只有当 RN 不高于 3 时它才有效。在去年的记录中,我发现它高达 32,但可以更高。

SELECT ORDER_NUM, TO_PRODUCE, PRODUCT_ID, RN, PRODUCED, SUBTRACTING, 
CASE WHEN RN = 1 AND (PRODUCED <= TO_PRODUCE OR LEAD(RN) OVER (PARTITION BY ORDER_NUM, PRODUCT_ID ORDER BY ORDER_NUM, PRODUCT_ID, RN) IS NULL) THEN PRODUCED
     WHEN RN = 1 AND PRODUCED > TO_PRODUCE THEN TO_PRODUCE
     WHEN LEAD(SUBTRACTING) OVER (PARTITION BY ORDER_NUM, PRODUCT_ID ORDER BY ORDER_NUM, PRODUCT_ID, RN) IS NULL AND SUBTRACTING > 0 THEN LAG(SUBTRACTING) OVER (PARTITION BY ORDER_NUM, PRODUCT_ID ORDER BY ORDER_NUM, PRODUCT_ID, RN)
     WHEN SUBTRACTING >= 0 AND LAG(SUBTRACTING) OVER (PARTITION BY ORDER_NUM, PRODUCT_ID ORDER BY ORDER_NUM, PRODUCT_ID, RN) > 0 THEN TO_PRODUCE
     WHEN SUBTRACTING < 0 AND LAG(SUBTRACTING) OVER (PARTITION BY ORDER_NUM, PRODUCT_ID ORDER BY ORDER_NUM, PRODUCT_ID, RN) > 0 THEN LAG(SUBTRACTING) OVER (PARTITION BY ORDER_NUM, PRODUCT_ID ORDER BY ORDER_NUM, PRODUCT_ID, RN) 
     ELSE 0
     END AS TRUE_PRODUCED        
FROM (  
WITH MY_TABLE AS (SELECT 'Order1' ORDER_NUM, 1000 TO_PRODUCE, 'ProductID1' PRODUCT_ID, 1 RN, 3500 PRODUCED, 3500 WPRODUCED FROM DUAL 
               UNION ALL
               SELECT 'Order1' ORDER_NUM, 1000 TO_PRODUCE, 'ProductID1' PRODUCT_ID, 2 RN, 0 PRODUCED, 3500 WPRODUCED FROM DUAL 
               UNION ALL
               SELECT 'Order1' ORDER_NUM, 1000 TO_PRODUCE, 'ProductID1' PRODUCT_ID, 3 RN, 0 PRODUCED, 3500 WPRODUCED FROM DUAL)
SELECT PRODUCT_ID, ORDER_NUM, TO_PRODUCE, PRODUCED, RN,
    CASE WHEN RN = 1 AND LEAD(RN) OVER (PARTITION BY ORDER_NUM, PRODUCT_ID ORDER BY ORDER_NUM, PRODUCT_ID, RN) IS NULL THEN PRODUCED 
        ELSE CASE WHEN RN = 1 AND PRODUCED > TO_PRODUCE AND LEAD(RN) OVER (PARTITION BY ORDER_NUM, PRODUCT_ID ORDER BY ORDER_NUM, PRODUCT_ID, RN) > 1 THEN PRODUCED - TO_PRODUCE
                        WHEN RN = 2 THEN LAG(PRODUCED - TO_PRODUCE) OVER (PARTITION BY ORDER_NUM, PRODUCT_ID ORDER BY ORDER_NUM, PRODUCT_ID, RN) - TO_PRODUCE
                        WHEN RN = 3 THEN LAG(PRODUCED - TO_PRODUCE, 2) OVER (PARTITION BY ORDER_NUM, PRODUCT_ID ORDER BY ORDER_NUM, PRODUCT_ID, RN) - LAG(TO_PRODUCE) OVER (PARTITION BY ORDER_NUM, PRODUCT_ID ORDER BY ORDER_NUM, PRODUCT_ID, RN) - TO_PRODUCE
            END 
        END AS SUBTRACTING FROM MY_TABLE ORDER BY RN
);

这个查询给了我一个输出:

ORDER_NUM TO_PRODUCE PRODUCT_ID RN PRODUCED SUBTRACTING TRUE_PRODUCED
Order1 1000 ProductID1 1 3500 2500 1000
Order1 1000 ProductID1 2 0 1500 1000
Order1 1000 ProductID1 3 0 500 1500

我想让 SUBTRACTING 对所有 RN 通用。我可以继续

WHEN RN = 4 THEN 
LAG(PRODUCED - TO_PRODUCE, 3) OVER (PARTITION BY ORDER_NUM, PRODUCT_ID ORDER BY ORDER_NUM, PRODUCT_ID, RN) 
- LAG(TO_PRODUCE, 2) OVER (PARTITION BY ORDER_NUM, PRODUCT_ID ORDER BY ORDER_NUM, PRODUCT_ID, RN)
- LAG(TO_PRODUCE) OVER (PARTITION BY ORDER_NUM, PRODUCT_ID ORDER BY ORDER_NUM, PRODUCT_ID, RN)
- TO_PRODUCE

并以类似方式继续,但我想有更好(更快)的方法。

你可以通过使用window功能更有效地做到这一点-

WITH MY_TABLE AS (SELECT 'Order1' ORDER_NUM, 1000 TO_PRODUCE, 'ProductID1' PRODUCT_ID, 1 RN, 3500 PRODUCED, 3500 WPRODUCED FROM DUAL 
                  UNION ALL
                  SELECT 'Order1' ORDER_NUM, 1000 TO_PRODUCE, 'ProductID1' PRODUCT_ID, 2 RN, 0 PRODUCED, 3500 WPRODUCED FROM DUAL 
                  UNION ALL
                  SELECT 'Order1' ORDER_NUM, 1000 TO_PRODUCE, 'ProductID1' PRODUCT_ID, 3 RN, 0 PRODUCED, 3500 WPRODUCED FROM DUAL)
SELECT ORDER_NUM, TO_PRODUCE, PRODUCT_ID, RN, PRODUCED,
       SUM(PRODUCED) OVER() - 
       SUM(TO_PRODUCE) OVER (ORDER BY RN) SUBTRACTING
  FROM MY_TABLE;

Demo.