【问题标题】:Finding total deductions based on sum of prior rows in SQL根据 SQL 中先前行的总和查找总扣除额
【发布时间】:2010-10-04 11:22:38
【问题描述】:

过去几天我一直在尝试解决一个相当棘手的问题。我目前正在使用 Oracle SQL 模型子句解决它,并且可能已经编写了一个函数,但我正在寻找一个使用分析函数或其他东西的简单解决方案,但无法解决任何问题。

对于给定的政策 (ddpsid),我想总结扣除列 (ddddpc)。 [对不起,难的列名,它们不是我的]。听起来很简单,但如果 ddbnep 列是“Y”,那么我想总结所有之前的扣除额,并将当前扣除额作为已扣除额的百分比。所以,如果当前扣除额是 10%,之前扣除额是 20%(即,还有 80% 剩余),那么我想扣除 8%(10% 或 80%),总共 28%。

下面的代码是我目前使用的:

with my_sample_data as (
  select 1 as ddpsid, ddddsq, ddddpc, ddbnep, ddadep
  from (
    select 1 as ddddsq, 10 as ddddpc, 'N' as ddbnep, 'Y' as ddadep from dual union all
    select 2 as ddddsq, 10 as ddddpc, 'Y' as ddbnep, 'Y' as ddadep from dual union all
    select 3 as ddddsq, 10 as ddddpc, 'N' as ddbnep, 'Y' as ddadep from dual union all
    select 4 as ddddsq, 10 as ddddpc, 'Y' as ddbnep, 'Y' as ddadep from dual
  )
)
--        select
--            ddpsid,
--            cumul as ddddpc
--        from (
          select
            ddpsid,
            ddddsq,
            ddadep,
            ddbnep,
            ddddpc,
            rn,
            num_rows,
            100 * (1-cumul) as cumul
          from my_sample_data a
          where ddadep = 'Y'
          model
          return all rows
          partition by (ddpsid)
          dimension by (row_number() over(partition by ddpsid order by ddddsq) as rn)
          measures (ddddsq, ddadep, ddddpc, ddbnep, 0 as cumul,
                        count(*) over(partition by ddpsid) as num_rows)
          rules automatic order (
            cumul[rn] = case
                          when nvl(ddbnep[cv(rn)],'N') = 'N'
                            then nvl(cumul[cv(rn)-1],1)- ddddpc[cv(rn)] /100
                          else nvl(cumul[cv(rn)-1],1)* (1- ddddpc[cv(rn)]/100) end
          )
--        )
--        where rn = num_rows

数据按ddpsid分组,按ddddsq顺序处理。 ddpsid 和 ddddsq 的组合应该是唯一的。扣除百分比在 ddddpc 列中。我只想处理 ddadep = 'Y' 的行。最后,如果 ddbnep 列 = 'N' 那么我只想将 ddddpc 添加到运行总计中,否则如果 ddbnep = 'Y' 我想将 ddddpc 作为(100% - 运行总计)的百分比并添加它到总和。

注释掉的代码是必要的,因为我真的只想要每个 ddpsid 的最后一个值,但如果没有它,它会显示工作得更好。

很抱歉这个问题太长了,但这是我能提供的最简洁的描述。

上面的代码显示了四个扣除,两个正常扣除和两个先验扣除。

  • 第一个为 10% 是正常的,运行总计为 10%。
  • 10% 的第二个是之前的净值。之前的扣除总额为 10%,因此剩余金额为 90%。所以这个扣除额应该是 9%,总共是 19%
  • 10% 的第三个是正常的,运行总计为 29%。
  • 10% 的最终值也扣除了先前值。之前的扣除总额为 29%,因此剩余金额为 71%。所以这个扣除额应该是 7.1%,总计 36.1%

在尝试了两三天来尝试找到一个 SQL 解决方案之后,我有点失望,我不能,希望我没有错过任何东西。

那么,有什么方法可以在不使用模型子句且不编写函数的情况下重写它?

【问题讨论】:

    标签: sql oracle oracle10g


    【解决方案1】:

    米奇,

    对于您的查询,您需要根据之前计算的值计算值。 这是一种只能使用 SQL 模型子句或递归子查询因式分解才能有效完成的操作。后者是在版本 11g 第 2 版中引入的。您可以阅读它here in the documentationhere in a blogpost of mine。 由于我不知道你使用的是什么版本,所以我不知道这个建议有多大用处。

    但是为什么要重写它而不使用模型子句呢?

    顺便说一句,如果你使用这个变体,你可以稍微简化你的查询:

    SQL> with my_sample_data as
      2  ( select 1 as ddpsid, ddddsq, ddddpc, ddbnep, ddadep
      3      from ( select 1 as ddddsq, 10 as ddddpc, 'N' as ddbnep, 'Y' as ddadep from dual union all
      4             select 2 as ddddsq, 10 as ddddpc, 'Y' as ddbnep, 'Y' as ddadep from dual union all
      5             select 3 as ddddsq, 10 as ddddpc, 'N' as ddbnep, 'Y' as ddadep from dual union all
      6             select 4 as ddddsq, 10 as ddddpc, 'Y' as ddbnep, 'Y' as ddadep from dual
      7           )
      8  )
      9  select ddpsid
     10       , ddddsq
     11       , 'Y' as ddadep
     12       , ddbnep
     13       , ddddpc
     14       , rn
     15       , num_rows
     16       , cumul
     17    from my_sample_data a
     18   where ddadep = 'Y'
     19   model
     20         partition by (ddpsid, count(*) over (partition by ddpsid) as num_rows)
     21         dimension by (row_number() over (partition by ddpsid order by ddddsq) as rn)
     22         measures (ddddsq, ddddpc, ddbnep, 0 as cumul)
     23         ( cumul[any] order by rn
     24           = case nvl(ddbnep[cv()],'N')
     25             when 'N' then
     26               nvl(cumul[cv()-1],0) + ddddpc[cv()]
     27             when 'Y' then
     28               100 - ((100 - nvl(cumul[cv()-1],0)) * (1-ddddpc[cv()]/100))
     29             end
     30         )
     31  /
    
        DDPSID     DDDDSQ D D     DDDDPC         RN   NUM_ROWS      CUMUL
    ---------- ---------- - - ---------- ---------- ---------- ----------
             1          1 Y N         10          1          4         10
             1          2 Y Y         10          2          4         19
             1          3 Y N         10          3          4         29
             1          4 Y Y         10          4          4       36.1
    
    4 rows selected.
    

    希望这会有所帮助。

    问候, 抢。

    【讨论】:

    • 我在 10.2,所以递归子查询分解是不可能的。以前从未使用过示范条款,因为我从未发现需要。并不是我不想使用它,我只是觉得必须有另一个我看不到的解决方案......但看起来没有。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-15
    • 2016-07-30
    • 2019-01-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多