Oracle sql在计算中使用前行数据

Posted

技术标签:

【中文标题】Oracle sql在计算中使用前行数据【英文标题】:Oracle sql using previous rows data in calculations 【发布时间】:2022-01-18 19:18:01 【问题描述】:

我有一个包含 06 列的表 T1,并希望使用选择查询获取新的两列。 这是我想要获得的带有两个额外列(STOCK、WAUC)的 T1:

CREATE TABLE T1 (MOUVEMENT NUMBER(2), OPERATION VARCHAR2(5), ITEM VARCHAR2(5), INPUT_QTY NUMBER(6, 2), OUTPUT_QTY NUMBER(6, 2), INPUT_PRICE NUMBER(6, 2), STOCK NUMBER(6, 2), WAUC NUMBER(6, 2));
INSERT ALL
INTO T1 VALUES(1, 'I', 'A', 1500,  0,      5,      1500,       5)
INTO T1 VALUES(2, 'I', 'A', 700,   0,      6,      2200,       5.31)
INTO T1 VALUES(3, 'O', 'A', 0,     800,    0,      1400,       5.31)
INTO T1 VALUES(4, 'I', 'A', 1000,  0,      5,      2400,       5.18)
INTO T1 VALUES(5, 'O', 'A', 0,     500,    0,      1900,       5.18)
INTO T1 VALUES(6, 'I', 'A', 1000,  0,      7,      2900,       5.8 )
INTO T1 VALUES(7, 'I', 'A', 2000,  0,      7,      4900,       6.28)
INTO T1 VALUES(8, 'I', 'A', 5000,  0,      7,      5400,       6.34)
INTO T1 VALUES(9, 'O', 'A', 0,     1000,   0,      4400,       6.34)
INTO T1 VALUES(10, 'I','A', 1000,  0,      5,      5400,       6.09)
SELECT 1 FROM DUAL;

WAUC 就像加权平均单位成本,用于评估我们的库存。

如果第一个记录:STOCK = INPUT 和 WAUC = INPUT_PRICE; 如果新 INPUT 操作:新 WAUC 应该是:(最后生成的 WAUC * 最后生成的库存)+(当前 INPUT * 当前 INPUT_PRICE))/当前生成的 STOCK。

Ex 第二行:WAUC = ((5 * 1500) + (700 * 6)) / 2200 = 5.31

万一新的 OUTPUT 操作:WAUC 应该是最后生成的 WAUC。

Ex 第三行:WAUC = 同一项目 A 的最后生成的 WAUC (5.31)。

意味着,每个新的 INPUT 操作都应更改 WAUC。 在我看来,STOCK 和 WAUC 应该即时生成,而不是作为记录, 因为否则,只有一个意外错误的 INPUT_PRICE,会导致下一次 WAUC 错误 -> 下一次计算错误 -> (错误工作)。

我怎样才能做到这一点? 提前致谢。

【问题讨论】:

【参考方案1】:

您的逻辑是需要model 子句的教科书示例,几乎可以按照您详细指定的方式重写为该子句(注意model 子句是野兽,要了解更多信息,请参阅here 或@987654322 @或here):

with t1 (mouvement, operation, item, input_qty, output_qty, input_price, stock_expected, wauc_expected) as (
 select 1, 'I', 'A', 1500,  0,      5,      1500,       5    from dual union all
 select 2, 'I', 'A', 700,   0,      6,      2200,       5.31 from dual union all
 select 3, 'O', 'A', 0,     800,    0,      1400,       5.31 from dual union all
 select 4, 'I', 'A', 1000,  0,      5,      2400,       5.18 from dual union all
 select 5, 'O', 'A', 0,     500,    0,      1900,       5.18 from dual union all
 select 6, 'I', 'A', 1000,  0,      7,      2900,       5.8  from dual union all
 select 7, 'I', 'A', 2000,  0,      7,      4900,       6.28 from dual union all
 select 8, 'I', 'A', 500,  0,      7,      5400,       6.34 from dual union all
 select 9, 'O', 'A', 0,     1000,   0,      4400,       6.34 from dual union all
 select 10, 'I','A', 1000,  0,      5,      5400,       6.09 from dual
)
select * from (
  select t1.*, 0 as stock_actual, 0 as wauc_actual from t1
)
model
  dimension by (row_number() over (order by mouvement) as rn)
  measures (mouvement, operation, item, input_qty, output_qty, input_price, stock_expected, wauc_expected, stock_actual, wauc_actual)
  rules (
    stock_actual[any] = coalesce(stock_actual[cv(rn) - 1], 0) + case operation[cv(rn)]
      when 'I' then input_qty[cv(rn)]
      when 'O' then -output_qty[cv(rn)]
    end,
    wauc_actual[any] = case
      when cv(rn) = 1
        then input_price[cv(rn)]
      when operation[cv(rn)] = 'I'
        then trunc((wauc_actual[cv(rn) - 1] * stock_actual[cv(rn) - 1] + input_qty[cv(rn)] * input_price[cv(rn)]) / stock_actual[cv(rn)], 2)
      when operation[cv(rn)] = 'O'
        then wauc_actual[cv(rn) - 1]
    end
  )
order by mouvement

(我将 operation=5000->500 中的拼写错误更改为 mouvement=8 并将截断添加到 2 位数字 - 这都是我从您的预期结果中猜到的。)

Db fiddle here.

请注意,简单的分析函数不足以计算wauc,因为它们只能访问输入数据集列的先前值,而不是函数本身计算的列值。对于stock,可以使用sum(input_qty) over (order by mouvement) - sum(output_qty) over (order by mouvement) 的运行总数,但对于wauc,几乎没有任何明确的公式。

【讨论】:

非常感谢你的回复,你真的救了我的命,这太有帮助了,我已经 3 天想弄清楚了。继续做这个人。 @HouariBoumediane 欢迎您。您提供了数据库供应商,清楚地描述了问题(我不明白“需要详细信息或清晰度”的原因),并提供了 SQL 代码示例,而不是格式漂亮的表格或 imgur 屏幕截图。不是每个 [sql] 提问者都这样做。这会吸引潜在帮助者的注意力并提高回答的机会,继续做这个人:-)

以上是关于Oracle sql在计算中使用前行数据的主要内容,如果未能解决你的问题,请参考以下文章

Oracle sql 错误 ora-01722 无效数字 ora-02063 前行来自

在 Case 语句中使用计算 - Oracle SQL

在选择语句计算Oracle SQL中使用列别名[重复]

如何使用 SQL 开发人员从另一台计算机访问安装在一台计算机上的 oracle db(以便 2 人可以在同一个数据库上协同工作)

如何在 oracle-sql 中计算周一待处理票的总数?

SQL:计算Oracle中多列的出现次数