问题
I have a data set like below,
Lot Size Reported QTY Qty Balance
150 100
150 100
150 80
150 80
150 5
The Qty Balance needs to calculated as follows,
Row 1 = Lot Size - Reported Qty (row1) => 150-100 = 50
Row 2 = Reported Qty (row1) - Reported Qty(row2) => 100-100 =0
Row 3 = Reported Qty (row2) - Reported Qty(row3) => 100-80 =20
... till the last row
My expected result is
Lot Size Reported QTY Qty Balance
150 100 50
150 100 0
150 80 20
150 80 0
150 5 75
How do I achieve this in a query?
回答1:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE lots ( Lot_Size, Reported_QTY ) AS
SELECT 150, 100 FROM DUAL
UNION ALL SELECT 150, 100 FROM DUAL
UNION ALL SELECT 150, 80 FROM DUAL
UNION ALL SELECT 150, 80 FROM DUAL
UNION ALL SELECT 150, 5 FROM DUAL;
Query 1:
SELECT Lot_Size,
Reported_QTY,
COALESCE( LAG( Reported_QTY ) OVER ( ORDER BY NULL ) - Reported_QTY,
Lot_Size - Reported_QTY ) AS Qty_Balance
FROM Lots
Results:
| LOT_SIZE | REPORTED_QTY | QTY_BALANCE |
|----------|--------------|-------------|
| 150 | 100 | 50 |
| 150 | 100 | 0 |
| 150 | 80 | 20 |
| 150 | 80 | 0 |
| 150 | 5 | 75 |
回答2:
You should take a look at the LAG()
analytic function. See here for details on the function and the parameters it accepts (for example, I think you're going to need to pass in a default of the lot_size column for when the lag() function returns null.)
Once you've identified the previous row's reported qty value, then you can simply subtract it. You will, of course, need some way of identifying the order of the rows - your sample data doesn't appear to have one, so the database won't be able to determine which row is first and which is last.
Eg.
with sample_data (lot_size, reported_qty) as (SELECT 150, 100 FROM DUAL
UNION ALL SELECT 150, 100 FROM DUAL
UNION ALL SELECT 150, 80 FROM DUAL
UNION ALL SELECT 150, 80 FROM DUAL
UNION ALL SELECT 150, 5 FROM DUAL)
select lot_size,
reported_qty,
lag(reported_qty, 1, lot_size) over (order by null) - reported_qty diff
from sample_data;
LOT_SIZE REPORTED_QTY DIFF
---------- ------------ ----------
150 100 50
150 100 0
150 80 20
150 80 0
150 5 75
回答3:
As @Boneist suggested, you need to use LAG() OVER() analytic function.
You just need to do one more task to handle the first row which will be NULL, using CASE you could make it work.
Test case
SQL> WITH data AS
2 ( SELECT t.*, lag(reported_qty) OVER(ORDER BY NULL) rn FROM t
3 )
4 SELECT lot_size,
5 reported_qty,
6 CASE
7 WHEN rn IS NULL
8 THEN lot_size - reported_qty
9 ELSE rn - reported_qty
10 END qty_balance
11 FROM data;
LOT_SIZE REPORTED_QTY QTY_BALANCE
---------- ------------ -----------
150 100 50
150 100 0
150 80 20
150 80 0
150 5 75
SQL>
来源:https://stackoverflow.com/questions/30374885/how-do-i-do-running-totals-from-second-column