【问题标题】:Preventing running total from going negative in Oracle防止在 Oracle 中运行总计变为负数
【发布时间】:2017-04-06 11:47:29
【问题描述】:

“金额”列第一行的值为 5,第二行的值为 -10。

有没有办法让 oracle 的 sum(amount) over() 函数在第二行返回 0 而不是 -5?

【问题讨论】:

  • 使用案例陈述。 case when windowfunction <0 then 0 else windowfunction end as Amount 或将其设为 CTE 并从 cte 中选择并在 case 语句中评估金额..
  • 但我希望 0 反映在以下行(第 3 行、第 4 行等)中。案例陈述对我没有帮助。
  • @Marko - 这就是为什么发布一些示例数据来解释您的示例会很有帮助
  • 作为 CTE,在窗口函数执行后评估每一行......是的,是的。
  • 您问,“有没有办法让 oracle 的 sum(amount) over() 函数在第二行返回 0 而不是 -5?”不可以。无法中断窗口函数并“重置”该值,也许使用单独的字段来保持与窗口函数无关的运行总数可能会起作用。我发现,使用递归 CTE 的不同方法提供了更大的灵活性,使这成为可能

标签: oracle function sum cumulative-sum analytical


【解决方案1】:

公然使用 Rajesh Chamarthi 的示例来源:但改变以显示更多的负面和正面......并展示一个案例如何将所有负面改变为零,同时保持其他数量......

with t as (
  select 5 as x, 1 as id from dual
  union all
  select -10, 2 as id from dual
  union all
  select 7, 3 as id from dual
  union all
  select -5, 4 as id from dual
  union all
  select -2, 5 as id from dual
),  
B as (select  t.x, 
        case when sum(x) over (order by id) < 0 then 0 
              else sum(x) over (order by id) 
        end Amount
 from t
 order by id)
 Select X, Case when amount < 0 then 0 else amount end as Amount from B;

  T   Amount
  5      5
-10      0
  7      2
 -5      0
 -2      0

----尝试 2(第一次尝试保留为下面的 cmets 引用它)

当金额低于 0 时,我不知道如何中断窗口函数以将值重置为 0...所以我使用了递归 CTE,它给了我更大的控制权。

如果 id 不是连续的,我们可以添加一个 row_Number,这样我们就有一个 ID 可以加入...或者我们可以使用 min() where > oldID。我假设我们有一个唯一键的唯一 ID,或者按照您希望总和发生的顺序对记录进行“排序”...

with aRaw as (
  select 5 as x, 15 as id from dual
  union all
  select -10, 20 as id from dual
  union all
  select 7, 32 as id from dual
  union all
  select 2, 46 as id from dual
  union all
  select -15, 55 as id from dual
  union all
  select 3, 68 as id from dual
),
t as (Select A.*, Row_number() over (order by ID) rn from aRAW A),

CTE(RN, ID, x, SumX) AS (
Select T.RN, T.ID, x, X from t WHERE ID = (Select min(ID) from t)
UNION ALL
Select T.RN, T.ID, T.X, case when T.X+CTE.SumX < 0 then 0 else T.X+Cte.sumX end from T
INNER JOIN CTE
 on  CTE.RN+1=T.RN)

Select * from cte;

.

  1. CTE:ARaw 只是一个样本数据集
  2. CTE:T 添加一个连续的行号,以防 ID 中存在间隙,从而允许在递归 CTE 上使用更简单的连接方法。
  3. CTE:CTE 是递归 CTE,它保持一个运行总计,并有一个 case 语句在运行总计低于 0 时将其重置为 0

【讨论】:

  • 所以你想在到达0时重新开始编号;明白了。
  • @Marko - 你可以忽略case语句中的负数,然后在上面求和..
  • Rajesh,这将在第二行给我 5 而不是 0(查看 xQbert 帖子中的结果表)
  • @marko 不,我知道没有办法在总和变为负数时中断窗口函数以将总和重置为零。但是,使用递归 CTE 进行求和,我们有更大的控制权,这成为可能。 (对不起,不得不做几个小时的真正工作!:P)
  • @xQbert,它就像一个魅力!我不知道递归 CTE 存在,我认为不可能用窗口函数来做到这一点。谢谢!
【解决方案2】:

您可以使用 case 语句,但这不是真正的累计

with t as (
  select 5 as x, 1 as id from dual
  union all
  select -10, 2 as id from dual
  union all
  select 20, 3 as id from dual
  union all
  select 30, 4 as id from dual
  union all
  select 10, 5 as id from dual
)  
select  t.x, 
        case when sum(x) over (order by id) < 0 then 0 
              else sum(x) over (order by id) 
        end running_total
 from t
 order by id;

X   RUNNING_TOTAL

5   5
-10 0
20  15
30  45
10  55

【讨论】:

    猜你喜欢
    • 2019-09-30
    • 2021-11-23
    • 1970-01-01
    • 1970-01-01
    • 2021-12-05
    • 2020-11-21
    • 2016-10-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多