简体   繁体   中英

Oracle PL/SQL : Accessing previous row calculated value in current row

Trying to calculate the column's value wherein the value is getting calculated based on previous row's calculated value. (As in the image below )

图片

which has column Z which is a calculated column as a product of X*Y, case when there is no previous row the value of Y column should be 1 else the value should be previous Z column value.

This can be achieved using Cursor's but trying to find it using SQL Query.

It looks like what you're trying to do is do a cumulative multiplication across all the rows.

You can do this by using a mathematical trick (aka natural logs and exponentials), where you do a cumulative sum of the natural logs of the x values, and then convert the results back to integers using the exponential function:

WITH your_table AS (SELECT 'ABC' a, 12 x FROM dual UNION ALL
                    SELECT 'BBC' a, 20 x FROM dual UNION ALL
                    SELECT 'CBC' a, 10 x FROM dual UNION ALL
                    SELECT 'XYZ' a, 5 x FROM dual)
 SELECT a,
       x,
       LAG(z, 1, 1) OVER (ORDER BY a) y,
       z
FROM   (SELECT a,
               x,
               EXP(SUM(LN(x)) OVER (ORDER BY a)) z
        FROM   your_table);

A            X          Y          Z
--- ---------- ---------- ----------
ABC         12          1         12
BBC         20         12        240
CBC         10        240       2400
XYZ          5       2400      12000

Then, if you need to see the previous value (aka your y column), you can throw a lag() around the calculated column to find the previous row's value (and if there is no previous row, assign a 1 to it).


ETA: If you already have a table with the information in it, adding a new row becomes a matter of finding the last row and using that to multiply with the new x value. Eg:

insert into your_table (a, x, y, z)
select 'YMX' a, 2 x, z as new_y, 2*z as new_z
from   (select z,
               row_number() over (order by a desc) rn
        from   your_table)
where  rn = 1;

This finds the latest row (we use the row_number() analytic function to label the rows, starting with the latest a value (which belongs to the last row)), and we can then use the z value from that row to find the new y value, and multiply it by the new x value to find the new z value.

Then you just need to insert this row.

I think the simplest method doesn't use lag() or a subquery at all. One method is simple division:

SELECT a, x, y
       ( EXP(SUM(LN(x * y)) OVER (ORDER BY a)) ) / (x * y) as z
FROM t;

Or use a window clause with coalesce() :

SELECT a, x, y
       COALESCE( EXP(SUM(LN(x * y)) OVER (ORDER BY a ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING)), 1 ) as z
FROM t;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM