4

如何从 SQL 查询中的前一行引用计算值?在我的情况下,每一行都是一个事件,它以某种方式操纵前一行的相同值。

原始数据如下所示:

Eventno 事件类型 Totalcharge
3 ACQ 32
2 出空
1 出空

假设每个 Eventtype=OUT 应该是名为 Remaincharge 的列中前一行总电荷的一半:

Eventno Eventtype Totalcharge Remaincharge
3 ACQ 32 32
2 出空 16
1 出空 8

我已经尝试过 LAG 分析函数,但这不允许我从前一行获得计算值。尝试过这样的事情:

LAG(remaincharge, 1, totalcharge) OVER (PARTITION BY ...) as remaincharge

但这不起作用,因为找不到剩余电荷。

任何想法如何实现这一目标?需要一个分析函数,它可以给我累积总和,但给定一个函数,而不是访问以前的值。

先感谢您!

更新问题描述

恐怕我的示例问题很笼统,这里有一个更好的问题描述:

剩余的总费用由outqty /(previous剩余数量)的比率决定。

Eventno Eventtype Totalcharge Remainqty Outqty
4 ACQ 32 100 0
3 其他 NULL 100 0
2 出空 60 40
1 输出空 0 60
Eventno Eventtype Totalcharge Remainqty Outqty Remaincharge
4 ACQ 32 100 0 32
3 其他 NULL 100 0 32 - (0/100 * 32) = 32
2 OUT NULL 60 40 32 - (40/100 * 32) = 12.8
1 OUT NULL 0 60 12.8 - (60/60 * 12.8) = 0
4

3 回答 3

4

在您的情况下,您可以使用FIRST_VALUE()分析函数和 2 的幂来计算第一个值,您必须在子查询中用RANK()除然后使用它。它对您的示例非常具体,但应该为您提供总体思路:

select eventno, eventtype, totalcharge
     , case when eventtype <> 'OUT' then firstcharge
            else firstcharge / power(2, "rank" - 1) 
       end as remaincharge
  from ( select a.*
              , first_value(totalcharge) over 
                  ( partition by 1 order by eventno desc ) as firstcharge
              , rank() over ( partition by 1 order by eventno desc ) as "rank"
           from the_table a
                )

这是一个要演示的SQL Fiddle 。我没有进行任何分区,因为您的原始数据中没有任何内容可以分区...

于 2013-04-22T09:45:25.227 回答
2

Ben 的使用窗口条款的答案的变体,它似乎可以满足您更新的要求:

select eventno, eventtype, totalcharge, remainingqty, outqty,
    initial_charge - case when running_outqty = 0 then 0
    else (running_outqty / 100) * initial_charge end as remainingcharge
from (
    select eventno, eventtype, totalcharge, remainingqty, outqty,
        first_value(totalcharge) over (partition by null
            order by eventno desc) as initial_charge,
        sum(outqty) over (partition by null
            order by eventno desc
            rows between unbounded preceding and current row)
            as running_outqty
    from t42
);

除了它给出19.2而不是12.8第三行,但这就是你的公式所建议的:

   EVENTNO EVENT TOTALCHARGE REMAININGQTY     OUTQTY REMAININGCHARGE
---------- ----- ----------- ------------ ---------- ---------------
         4 ACQ            32          100          0              32
         3 OTHER                      100          0              32
         2 OUT                         60         40            19.2
         1 OUT                          0         60               0

如果我添加另一个拆分,使其分两步从 60 变为零,并且混合中还有另一个非 OUT 记录:

   EVENTNO EVENT TOTALCHARGE REMAININGQTY     OUTQTY REMAININGCHARGE
---------- ----- ----------- ------------ ---------- ---------------
         6 ACQ            32          100          0              32
         5 OTHER                      100          0              32
         4 OUT                         60         40            19.2
         3 OUT                         30         30             9.6
         2 OTHER                       30          0             9.6
         1 OUT                          0         30               0

假设剩余数量是一致的,并且您可以有效地跟踪以前的运行总数,但从您显示的数据来看,这看起来是合理的。内部查询计算每一行的运行总计,外部查询进行计算;可以浓缩,但希望像这样更清晰......

于 2013-04-22T12:23:12.850 回答
1

本的答案是更好的(可能会表现更好),但你也可以这样做:

select t.*, (connect_by_root Totalcharge) / power (2,level-1) Remaincharge
from the_table t
start with EVENTTYPE = 'ACQ'
connect by prior eventno = eventno + 1;

我认为它更容易阅读

这是一个演示

于 2013-04-22T10:14:20.690 回答