在Oracle中将总和和大小写作为循环正确运行

时间:2018-10-01 17:38:19

标签: oracle function plsql

我正在遍历一个表格,以应税为参数来计算 IncomeTax 。因此,循环遍历表格,计算并求和。我被困在sum语句中应税金额小于累计金额的地方,然后将应税金额*百分比相乘。该示例说明了该功能我需要。例如

taxable=2000,
do 2000-261=1739 and do 0% * 261 = 0,
go to next line do 1739-70=1669 and do 5% * 70=3.5,
go to next line do 1669-100=1569 and do 10% *100.
go to next line,do 1569 < 2810, it should be 1569 *17.5%

multiply percentage by cummulative amount

CREATE OR REPLACE function CalculateIncomeTax2(taxableIncome NUMBER)
return NUMBER 
AS
IncomeTax NUMBER (10,2); 
BEGIN
SELECT 
 coalesce(SUM(     
  CASE WHEN (taxableIncome > T.TAX_CUMMULATIVE_AMOUNT) THEN ( 
(T.TAX_CUMMULATIVE_AMOUNT* T.TAX_PERCENTAGE)/ 100)                         
 ELSE 0.00 END
    ) ,0)                 
INTO IncomeTax
  FROM TAX_LAW T  

return IncomeTax
end; /

1 个答案:

答案 0 :(得分:1)

因此,您正在编写PL / SQL函数,但尝试使用普通的SQL查询来完成所有逻辑。我认为使用SQL查询当然可以做到这一点,但由于您的原始逻辑是循环结构,因此使用PL / SQL循环结构可能会更轻松。

CREATE OR REPLACE function CalculateIncomeTax2(taxableIncome NUMBER)
return NUMBER 
AS
    IncomeTax NUMBER (10,2) := 0;
    TaxableRemainder NUMBER := taxableIncome;
BEGIN
    for r in (select tax_id, tax_percentage, tax_cummulative_amount
              from incometax
              order by tax_id)
    loop
        if TaxableRemainder > r.tax_cummulative_amount then
            TaxableRemainder := TaxableRemainder - r.tax_cummulative_amount;
            incometax := incometax + (r.tax_cummulative_amount * r.tax_percentage / 100);
        else
            incometax := incometax + (TaxableRemainder * r.tax_percentage / 100);
            exit; 
        end if;
    end loop;

    return IncomeTax;
end; 
/

例如,我得到CalculateIncomeTax2(2000) = 288.08。这与您通常使用计算器(288.075)所获得的稍有不同,因为您将IncomeTax定义为NUMBER(10,2),精度为2。但这也许就是您想要的?

编辑:因此,在您的SQL查询中,您主要缺少的是为了保持每一行税额的运行总额,您需要一个analytic / window function 。这是一个示例,说明如何在普通SQL查询中执行相同的计算。 (您可以大大简化此查询,但是我认为这种方式更具可读性-您可以轻松地查看子查询以查看数据是如何构建的。)

select sum(tax_component)
from (
    select tax_id, tax_percentage, tax_cummulative_amount,
        taxableRemainder,
        case when taxableRemainder > tax_cummulative_amount 
            then (tax_cummulative_amount * tax_percentage / 100)
            else (taxableRemainder * tax_percentage / 100)
            end as tax_component
    from (
        select tax_id, tax_percentage, tax_cummulative_amount,
            nvl(2000-sum(tax_cummulative_amount) 
                     over (order by tax_id 
                        rows between unbounded preceding and 1 preceding),
                2000) 
                as taxableRemainder
        from incometax) it
)
;