【问题标题】:How do I write a sql statement to calculate totals, based on groups from another table?如何根据另一个表中的组编写 sql 语句来计算总数?
【发布时间】:2011-05-06 16:42:38
【问题描述】:

我需要根据累积值计算百分比。应用于每行中每个值的百分比取决于从另一个表中获取的百分比。百分比计算需要以分层方式进行,因为税收可能是根据收入计算的。

例如: 工资 = 1000
600 * 10% [前 600 美元按较低税率计算]
400 * 30% [按较高税率计算的剩余金额]

所以,我一直试图让它工作,但无法解决。 DBA 不在,所以交给我了。大多数 SQL 我都可以,但我不知道如何解决这个问题,或者我应该在谷歌中搜索什么,所以很抱歉这是一个简单的搜索,请直接指向 URL,我我会自己尝试解决的!

不管怎样,下面是数据表 (#v) 的格式示例和范围表 (#tiers) 的示例,以及我到目前为止的进展情况。我需要一个新列,它按照我上面解释的正确百分比层计算“cval”。

希望有人可以帮助或为我指明正确的方向! 谢谢,J。

create table #v(
id nvarchar(50),
val money,
tid int
)

insert into #v values ('a',30,1)
insert into #v values ('b',50,1)
insert into #v values ('c',10,1)
insert into #v values ('d',30,1)
insert into #v values ('e',-80,1)


create table #tiers (
tid int,
threshold money,
amount money
)

insert into #tiers values (1,0,30)
insert into #tiers values (1,40,40)
insert into #tiers values (1,100,50)


select * from
(
select v1.id, v1.tid, v1.val,sum(v2.val) cval
from #v v1
inner join #v v2 on v1.id >= v2.id
group by v1.id, v1.val, v1.tid
) a
left join
(
       select a.tid, a.id, a.threshold [lower], b.threshold [upper] from
       (
               select rank() over (order by threshold) as id, tid, threshold, amount from #tiers
       ) a
       left join
       (
               select rank() over (order by threshold) as id, tid, threshold, amount from #tiers
       ) b on a.id = b.id-1
) b on (a.cval >= lower and a.cval < upper) or (a.cval >= lower and upper is null)

【问题讨论】:

    标签: sql sql-server tsql


    【解决方案1】:

    如果你的实际逻辑有比这个更多的规则,你最好用像 PL/SQL 或 T-SQL 这样的过程语言来编写这个,因为很有可能......其他应用程序可能希望使用这个逻辑来使用......说.. *get_tax_for_pay(i_pay)* 或类似的东西。

    但如果这就是你所需要的,那么下面的 SQL 应该就足够了。

    在 Oracle 中对此进行了测试,因为我目前无法访问 SQL Server。如果您有任何问题,请在 cmets 中发布。 备注在最后。

    create table gross_pay(
      pay number);
    
    insert into gross_pay values (1523);
    insert into gross_pay values (500);
    insert into gross_pay values (5600);
    insert into gross_pay values (3523);
    commit;
    
    create table tax_range(
      min_pay number,
      max_pay number,
      tax_percent number);
    
    insert into tax_range values (1000, 2000, 10);
    insert into tax_range values (2000, 3000, 20);
    insert into tax_range values (3000, 4000, 30);
    insert into tax_range values (4000, 100000, 35);
    commit;
    
    SQL> select * from gross_pay;
    
           PAY
    ----------
          1523
           500
          5600
          3523
    
    SQL> select * from tax_range;
    
       MIN_PAY    MAX_PAY TAX_PERCENT
    ---------- ---------- -----------
          1000       2000          10
          2000       3000          20
          3000       4000          30
          4000     100000          35
    
    select g.pay, t.min_pay, t.max_pay, t.tax_percent,
      (g.pay-t.min_pay) diff, (t.max_pay-t.min_pay) diff2,
      (case when g.pay > t.min_pay then
            least((t.max_pay-t.min_pay),(g.pay-t.min_pay))
            else 0
        end) Taxable
      from gross_pay g, tax_range t
      order by pay, min_pay
    SQL> /
    
           PAY    MIN_PAY    MAX_PAY TAX_PERCENT       DIFF      DIFF2    TAXABLE
    ---------- ---------- ---------- ----------- ---------- ---------- ----------
           500       1000       2000          10       -500       1000          0
           500       2000       3000          20      -1500       1000          0
           500       3000       4000          30      -2500       1000          0
           500       4000     100000          35      -3500      96000          0
          1523       1000       2000          10        523       1000        523
          1523       2000       3000          20       -477       1000          0
          1523       3000       4000          30      -1477       1000          0
          1523       4000     100000          35      -2477      96000          0
          3523       1000       2000          10       2523       1000       1000
          3523       2000       3000          20       1523       1000       1000
          3523       3000       4000          30        523       1000        523
    
           PAY    MIN_PAY    MAX_PAY TAX_PERCENT       DIFF      DIFF2    TAXABLE
    ---------- ---------- ---------- ----------- ---------- ---------- ----------
          3523       4000     100000          35       -477      96000          0
          5600       1000       2000          10       4600       1000       1000
          5600       2000       3000          20       3600       1000       1000
          5600       3000       4000          30       2600       1000       1000
          5600       4000     100000          35       1600      96000       1600
    
     select pay, sum(tax) from (
     select pay, min_pay, max_pay, tax_percent, Taxable,
            (Taxable* tax_percent/100) tax from (
     select g.pay, t.min_pay, t.max_pay, t.tax_percent,
            (g.pay-t.min_pay) diff, (t.max_pay-t.min_pay) diff2,
            (case when g.pay > t.min_pay then
                  least((t.max_pay-t.min_pay),(g.pay-t.min_pay))
                  else 0
             end) Taxable
       from gross_pay g, tax_range t
       order by pay, min_pay
    
           PAY   SUM(TAX)
    ---------- ----------
          1523       52.3
          3523      456.9
           500          0
          5600       1160
    

    为了计算……

    1. 您只对特定薪酬超过税级给定阈值的金额征税感兴趣。示例.. 3k-5k 税级中的 1000 美元不会被征税。

    2. 如果金额超过阈值,您将收取最低金额 a) (max-min) 在那个阈值 b) (最低工资门槛) 所以。对于 5500 的工资,您只需在 1000-2000 美元的税级中收取 1000 美元。 对于 1200 的工资,您只需在 1000-2000 美元的税级中收取 200 美元。

    3. 如果您在不同的列中没有最小值和最大值,则可以使用超前/滞后函数或自联接将它们都放在我的测试表中的同一行中。如果最后一个范围没有最大值,请使用 NVL 或相应的函数分配一个非常大的值来定义范围。 (或空值代码:))

    【讨论】:

    • 感谢您的回答,但我使用了 Thomas 的回答,因为它更接近我的原始帖子。另外,我无法测试你的,因为 MS Sql 不支持你使用的某些语法。
    • 没问题。我想我也学到了一些试图回答这个问题的东西......而且我只能访问 Oracle。我同意.. Thomas 的帖子可能会对您有更多帮助。祝你好运!
    【解决方案2】:

    假设 Tiers 表中的 Amount 列应该是税率,您可以执行以下操作:

    With VData As
        (
        Select V1.id, V1.val, V1.tid, Sum(V2.val) As CVal
        From #V As V1
            Join #V As V2
                On V2.id <= V1.id
        Group By V1.id, V1.val, V1.tid
        )
        , Tiers As
        (
        Select T1.tid
            , T1.Amount
            , T1.threshold As MinThreshold
            , Min(Coalesce(T2.threshold, 2147483647)) As MaxThreshold
        From #tiers As T1
            Left Join #tiers As T2
                On T2.threshold > T1.threshold
        Group By T1.tid, T1.Amount, T1.threshold
        )
    Select V.id, V.val, V.tid, V.CVal
        , Sum(
            Case
            When CVal > T.MaxThreshold Then T.Amount / 100.00 * T.MaxThreshold
            When CVal >= T.MinThreshold Then T.Amount / 100.00 * (V.CVal - T.MinThreshold)
            End) As TotalTax
    From VData As V
        Join Tiers As T
            On T.tid = V.tid
    Group By V.id, V.val, V.tid, V.CVal
    

    【讨论】:

    • 标记为正确,因为我用它来编辑我的原始帖子以提供我想要的解决方案。
    猜你喜欢
    • 2023-04-06
    • 2021-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-07
    • 2012-08-30
    • 1970-01-01
    相关资源
    最近更新 更多