根据 SQL 中先前行的总和查找总扣除额

发布于 2024-09-26 03:41:28 字数 2412 浏览 2 评论 0原文

我有一个相当棘手的问题,过去几天我一直在努力解决。我目前正在使用 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 解决方案后,我有点失望,因为我不能,并且希望我没有错过任何事情。

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

I've got a rather tricky problem that I've been trying to solve for the past few days. I am currently solving it with the Oracle SQL Model clause and could probably have written a function but I'm looking for a nice simple solution using analytic functions or something but can't figure anything out.

For a given policy (ddpsid), I want to sum up the deductions column (ddddpc). [Sorry about the difficult column names, they are not mine]. Sounds simple, but if the ddbnep column is 'Y' then I want to sum up all the prior deductions and take the current deduction as a percentage of what has already been deducted. So, if the current deduction is 10% and the prior deductions are 20% (i.e., there is 80% remaining), then I want to deduct 8% (10% or 80%), for a total of 28%.

The code below is what I am currently using:

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

The data is to be grouped by ddpsid, and processed in order of ddddsq. The combination of ddpsid and ddddsq should be unique. The deduction percentage is in the ddddpc column. I only want to process rows where ddadep = 'Y'. And finally, if the ddbnep column = 'N' then I want to just add ddddpc to the running total, otherwise if ddbnep = 'Y' I want to take ddddpc as a percentage of (100% - the running total) and add it to the running total.

The code commented out is necessary because I really only want the last value for each ddpsid but it shows the working a bit better without that.

Sorry about the long question but it is about the most concise description I can provide.

The code above shows four deductions, two normal ones and two net of prior.

  • The first at 10% is normal and gives a running total of 10%.
  • The second at 10% is net of prior. The prior deductions summed to 10% so there is a remaining amount of 90%. So this deduction should be 9%, giving a running total of 19%
  • The third at 10% is normal and gives a running total of 29%.
  • The final at 10% is also net of prior. The prior deductions summed to 29% so there is a remaining amount of 71%. So this deduction should be 7.1%, giving a running total of 36.1%

After trying for two or three days to try and find a SQL solution to this, I'm a little disappointed that I couldn't and am hoping I didn't miss anything.

So, is there any way to rewrite this without using the model clause and without writing a function?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一抹微笑 2024-10-03 03:41:28

Mikey,

对于您的查询,您需要根据之前计算的值来计算值。
这种类型的操作只能使用 SQL 模型子句或递归子查询因子分解才能有效完成。后者是在版本 11g Release 2 中引入的。您可以阅读有关它 在博客文章中我的
由于我不知道你用的是什么版本,所以我不知道这个建议有多大用处。

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

顺便说一句,如果使用此变体,您可以稍微简化查询:

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.

希望这会有所帮助。

问候,
抢。

Mikey,

For your query, you need to calculate values based on previously calculated values.
This is a type of operation that can only be effectively done using the SQL Model Clause or with the Recursive Subquery Factoring. The latter was introduced in version 11g Release 2. You can read about it here in the documentation and here in a blogpost of mine.
Since I don't know what version you are on, I don't know how useful this suggestion is.

But why do you want to rewrite it without using the model clause?

By the way, you can simplify your query somewhat if you use this variant:

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.

Hope this helps.

Regards,
Rob.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文