防止运行总计变为负数-SQL Server

时间:2019-05-13 13:07:19

标签: sql sql-server performance cumulative-sum

我有一个包含以下值的表;

Earnings Penalties
1000     500
0        500
0        100
0        100
500      100
400      500

每当cumulative总和(收入-罚金)值大于或等于0时,将仅应用罚款。否则应为零。

我不需要使用CursorWhile循环的任何查询。我需要高性能的查询。

我想要下面的结果,

AttDay        Earnings Penalties IsPenaltyApplicable Reason
2019-05-01    1000     500       Yes                 (1000-500=500) Remaining 500
2019-05-02    0        500       Yes                 (500-500=0) Remaining 0
2019-05-03    0        100       Yes                 (0-100=-100) Remaining -100
2019-05-04    0        100       No                  0
2019-05-05    500      100       Yes                 (500-100=400) Remaining 400
2019-05-06    400      500       Yes                 (400-500=-100) Remaining -100

3 个答案:

答案 0 :(得分:1)

CASE .. WHEN ..将适用于同一情况。

CREATE TABLE #penaltytest
    (
    Earnings NUMERIC(7,2),
    Penalties NUMERIC(7,2)

    )

    INSERT INTO #penaltytest VALUES (1000,500)
    INSERT INTO #penaltytest VALUES (0,500)
    INSERT INTO #penaltytest VALUES (0,100)
    INSERT INTO #penaltytest VALUES (0,100)
    INSERT INTO #penaltytest VALUES (500,100)
    INSERT INTO #penaltytest VALUES (400,500)

    SELECT *,CASE WHEN (Earnings-Penalties) >0 THEN 'Yes' ELSE 'No' END AS 'IsPenaltyApplicable',CASE WHEN (Earnings-Penalties) >0 THEN (Earnings-Penalties) ELSE 0 END AS PenaltyAmount  FROM #penaltytest

答案 1 :(得分:1)

CREATE TABLE #penaltytest
    (
    Earnings NUMERIC(7,2),
    Penalties NUMERIC(7,2),
    AttDate DATE
    )

    INSERT INTO #penaltytest VALUES (1000,500, '01 Jan 2000')
    INSERT INTO #penaltytest VALUES (0,500, '02 Jan 2000')
    INSERT INTO #penaltytest VALUES (0,100, '03 Jan 2000')
    INSERT INTO #penaltytest VALUES (0,100, '04 Jan 2000')
    INSERT INTO #penaltytest VALUES (500,100, '05 Jan 2000')
    INSERT INTO #penaltytest VALUES (400,500, '06 Jan 2000')

;with cte as(
select
            AttDate,
            Earnings,
            Penalties,
            Earnings - Penalties as subTotal,           
            (select 
                        isnull(sum(Earnings - Penalties),0)
                from 
                        #penaltytest previousRow
                where
                        previousRow.AttDate < currentRow.AttDate                
            ) as cumulative
    from 
            #penaltytest currentRow 
)
select
            t.AttDate
            ,t.Earnings
            ,t.Penalties
            ,cte.subTotal
            ,cte.cumulative
            ,case when cte.cumulative - (t.Earnings - t.Penalties) >= 0 then 'Yes' else 'No' end as Penalty
    from #penaltytest t
        join cte
            on cte.AttDate = t.AttDate
drop table #penaltytest



Results:
AttDate Earnings    Penalties   subTotal    cumulative  Penalty
2000-01-01  1000.00 500.00  500.00  0.00    No
2000-01-02  0.00    500.00  -500.00 500.00  Yes
2000-01-03  0.00    100.00  -100.00 0.00    Yes
2000-01-04  0.00    100.00  -100.00 -100.00 Yes
2000-01-05  500.00  100.00  400.00  -200.00 No
2000-01-06  400.00  500.00  -100.00 200.00  Yes

答案 2 :(得分:0)

我将使用累积方法:

select pt.*, 
      sum(case when IsPenaltyApplicable = 1 then Earnings - Penalties else 0 end) over (partition by grp order by AttDay)
from (select t.*, sum(case when IsPenaltyApplicable = 0 then 1 else 0 end) over (order by AttDay) as grp
      from table t
     ) pt;