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;
假设我有一个 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;