【问题标题】:How to recursively compute ratio of remaining amounts based on rounded values from preceding rows?如何根据前行的舍入值递归计算剩余金额的比率?
【发布时间】:2012-07-12 08:13:53
【问题描述】:

我需要将 1 个金额分成 2 个字段。我知道结果字段的总和 = 分割第一行的比率,但我需要将结果总和舍入,然后才计算下一行的比率(所以四舍五入的总和值将是正确的)。

如何在 Oracle 10g PL/SQL 中编写此算法?我需要测试一些迁移的数据。这是我想出的(到目前为止):

with temp as (
  select 1 id, 200 amount, 642 total_a from dual union all
  select 2, 200, 642 from dual union all
  select 3, 200, 642 from dual union all
  select 4, 200, 642 from dual union all
  select 5, 200, 642 from dual
)
select
  temp2.*,
  remaining_a / remaining_amount ratio,
  round(amount * remaining_a / remaining_amount, 0) rounded_a,
  round(amount - amount * remaining_a / remaining_amount, 0) rounded_b
from (
  select
    temp.id,  
    temp.amount,
    sum(amount) over (
      order by id
      range between current row and unbounded following
    ) remaining_amount,
    case when id=1 then total_a /* else ??? */ end remaining_a
  from temp
) temp2

更新:如果您看不到上面的图片,预计 rounded_A 值为:

1 128
2 129
3 128
4 129
5 128

【问题讨论】:

  • 分配... 仅使用 SQL 并不容易。在 CURSOR 循环而不是 SQL 语句中可能值得这样做。
  • @NWest 任何 PL/SQL,我只是在 PL 部分没有足够的经验来自己弄清楚;) 哦 - 简单选择 1 份合同需要一些秒,我需要解决所有 100 000 条记录的解决方案,以便在几个小时内完成,而不是几天......
  • 给定TEMP 中的示例输入,您想要的输出是什么?
  • 您可以这样做,至少对于您提供的数据而言。在不知道如何在 Oracle 中使用查询进行查询之前,您的真实数据是否与此相同,每天的数量相同,所有日期的比例相同?
  • @JustinCave 图片中的 Rounded_ARounded_B

标签: sql recursion oracle10g


【解决方案1】:

这是我的建议。它没有得到你想要的。 . .根据我的计算,129 直到第 3 行才出现。

这个想法是添加更多列。对于每一行,计算估计的拆分。然后,跟踪累积分数。当 cum 余数超过一个整数时,将 A 金额增加 1。一旦有了 A 金额,您就可以计算余数:

WITH temp AS (
     SELECT 1 id, 200 amount, 642 total_a FROM dual UNION ALL
     SELECT 2, 200, 642 FROM dual UNION ALL
     SELECT 3, 200, 642 FROM dual UNION ALL
     SELECT 4, 200, 642 FROM dual UNION ALL
     SELECT 5, 200, 642 FROM dual
)
select temp3.*,
       sum(estArem) over (order by id) as cumrem,
       trunc(estA) + (case when trunc(sum(estArem) over (order by id)) > trunc(- estArem + sum(estArem) over (order by id))
                          then 1 else 0 end)
from (SELECT temp2.*,
             trunc(Aratio*amount) as estA,
             Aratio*amount - trunc(ARatio*amount) as estArem
      FROM (SELECT temp.id, temp.amount,
                   sum(amount) over (ORDER BY id range BETWEEN CURRENT ROW AND unbounded following
                              ) remaining_amount,
                   sum(amount) over (partition by null) as total_amount,      
                   max(total_a) over (partition by null)as maxA, 
                   (max(total_a) over (partition by null) /
                    sum(amount) over (partition by null)
                   )  as ARatio
            FROM temp
           ) temp2
      ) temp3

这不完全是分区问题。这是一个整数逼近问题。

如果您要对值进行舍入而不是截断它们,那么您需要对逻辑稍作调整。

       trunc(estA) + (case when trunc(sum(0.5+estArem) over (order by id)) > trunc(0.5 - estArem + sum(estArem) over (order by id))

这个语句最初只是寻找超过整数阈值的累积余数。这应该进行舍入而不是截断。

【讨论】:

  • +1,但我必须检查我是否可以让它工作 - 第二行应该是:200 * (642 - 128) / 800 = 128.5 => roded 值是 129,,通过四舍五入的值来表示任意精度,而不是整数 - 但从技术上讲,它几乎是一样的,谢谢你的提示:)
猜你喜欢
  • 1970-01-01
  • 2022-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-22
  • 1970-01-01
相关资源
最近更新 更多