以逐组为基础运行循环的任何方法,在每个组都经过SQL之后会重置变量吗?

问题描述 投票:0回答:1

我试图做的基础基本上是让我创建的循环遍历表,但按组运行((将由每个Manager运行,然后重置变量并运行,直到不再运行)经理存在)。

以下是用于CURSOR循环的代码:

--Setting up table for LOOP 
DECLARE @Running TABLE(BASManagerName VARCHAR(150), YearMonthDay DATE, CommissionAmount NUMERIC(16,2), LeftOverAmount NUMERIC(16,2), RunningTotal NUMERIC(16,2), Threshold INT, Payout NUMERIC(16,2), MyCounter INT)


DECLARE HotelThreshold CURSOR LOCAL
FOR
    SELECT RowGrouping ,BASManagerName ,YearMonthDay ,CommissionAmount
    FROM #HotelSumsNEWYearMonth
    ORDER BY RowGrouping, BASManagerName, YearMonthDay

DECLARE @Rank INT
    ,@CursorManager VARCHAR(150)
    ,@YearMonthDay DATE
    ,@Total NUMERIC(16,2)
    ,@Threshold INT
    ,@LeftOverAmount NUMERIC(16,2)
    ,@RunningTotal NUMERIC(16,2)
    ,@Payout NUMERIC(16,2)
    ,@MyCounter INT

    SET @Total = 0
    SET @LeftOverAmount = 0
    SET @RunningTotal = 0
    SET @MyCounter = 0
    SET @Payout = 0
    SET @Threshold = 0

OPEN HotelThreshold

    FETCH NEXT FROM HotelThreshold INTO @Rank, @CursorManager, @YearMonthDay, @Total
    WHILE @@FETCH_STATUS = 0
    BEGIN

        IF CAST((@LeftOverAmount + @Total) / 50000 AS INT) < 1
        BEGIN
            SET @RunningTotal = (@LeftOverAmount + @Total)
            SET @Threshold = 0 
            SET @Payout = 0
            SET @LeftOverAmount = @RunningTotal - (@Threshold * 50000)
            SET @MyCounter = @MyCounter + 1 
        END
        ELSE IF CAST((@LeftOverAmount + @Total) / 50000 AS INT) >= 1
        BEGIN
            SET @RunningTotal = (@LeftOverAmount + @Total) 
            SET @Threshold = CASE WHEN CAST(@RunningTotal / 50000 AS INT) >= 1 THEN CAST(@RunningTotal / 50000 AS INT) * 1 ELSE 0 END
            SET @Payout = @Threshold * 2500
            SET @LeftOverAmount = @RunningTotal - (@Threshold * 50000)
            SET @MyCounter = @MyCounter + 1 
        END

        INSERT @Running VALUES (@CursorManager, @YearMonthDay, @Total, @LeftOverAmount, @RunningTotal, @Threshold, @Payout, @MyCounter)
        FETCH NEXT FROM HotelThreshold INTO @Rank, @CursorManager, @YearMonthDay, @Total

    END 
CLOSE HotelThreshold
DEALLOCATE HotelThreshold


DROP TABLE #NewRunning
SELECT *
INTO #NewRunning
FROM @Running

SELECT * FROM #NewRunning

这里是#HotelSumsNewYearMonth表的DDL,该表填充了Cursor以及表中数据的示例:

enter image description here

+-------------+----------------+--------------+-----------+------------------+
| RowGrouping | BASManagerName | YearMonthDay | YearMonth | CommissionAmount |
+-------------+----------------+--------------+-----------+------------------+
|           1 | Debbie         | 7/1/2019     | 2019-07   |         33508.83 |
|           1 | Debbie         | 8/1/2019     | 2019-08   |         34240.37 |
|           1 | Debbie         | 9/1/2019     | 2019-09   |         19282.73 |
|           1 | Debbie         | 10/1/2019    | 2019-10   |                0 |
|           1 | Debbie         | 11/1/2019    | 2019-11   |                0 |
|           2 | Pam            | 7/1/2019     | 2019-07   |           321.23 |
|           2 | Pam            | 8/1/2019     | 2019-08   |           952.89 |
|           2 | Pam            | 9/1/2019     | 2019-09   |           601.84 |
|           2 | Pam            | 10/1/2019    | 2019-10   |            56.94 |
|           2 | Pam            | 11/1/2019    | 2019-11   |            76.83 |
+-------------+----------------+--------------+-----------+------------------+

循环代码的实现说明:

循环实现的结果是,它将创建BASManager每月赚取的佣金的连续总额。但是有一条条款规定,如果佣金超过5万,他们将在该月收到2500的付款。然后必须要做的是,达到50K后的一个月的运行总计,但是我会从运行总计中减去该阈值达到目标的很多倍,并从那时开始一直保持滚动。

输出错误,因为循环仅针对整个表而不是针对每个组运行:

+----------------+--------------+------------------+----------------+--------------+-----------+--------+-----------+
| BASManagerName | YearMonthDay | CommissionAmount | LeftOverAmount | RunningTotal | Threshold | Payout | MyCounter |
+----------------+--------------+------------------+----------------+--------------+-----------+--------+-----------+
| Debbie         | 7/1/2019     |         33508.83 |       33508.83 |     33508.83 |         0 |      0 |         1 |
| Debbie         | 8/1/2019     |         34240.37 |        17749.2 |      67749.2 |         1 |   2500 |         2 |
| Debbie         | 9/1/2019     |         19282.73 |       37031.93 |     37031.93 |         0 |      0 |         3 |
| Debbie         | 10/1/2019    |                0 |       37031.93 |     37031.93 |         0 |      0 |         4 |
| Debbie         | 11/1/2019    |                0 |       37031.93 |     37031.93 |         0 |      0 |         5 |
| Pam            | 7/1/2019     |           321.23 |       37353.16 |     37353.16 |         0 |      0 |         6 |
| Pam            | 8/1/2019     |           952.89 |       38306.05 |     38306.05 |         0 |      0 |         7 |
| Pam            | 9/1/2019     |           601.84 |       38907.89 |     38907.89 |         0 |      0 |         8 |
| Pam            | 10/1/2019    |            56.94 |       38964.83 |     38964.83 |         0 |      0 |         9 |
| Pam            | 11/1/2019    |            76.83 |       39041.66 |     39041.66 |         0 |      0 |        10 |
+----------------+--------------+------------------+----------------+--------------+-----------+--------+-----------+

[您可以看到Debbie的运行总金额处于37031.93的正确点,她已经在2019年8月1日收到付款,金额超过50,000,然后从运行总金额中减去50,000,再减去下个月的余额佣金总计为37031.93。

[我想/需要发生的事情]十一月过去了,一旦循环开始,Pam的运行便是将变量重置为0并从Pam的数据重新开始。但是,您可以看到当前它正在保持Debbie的运行总计,并以此为基础来开始Pam的计算。

sql loops tsql while-loop database-cursor
1个回答
0
投票

使用窗口功能!游标不是必需的,大多数多余的列也不需要。

select t.*,
       (floor(running_commissionamount / 50000) - floor( (running_commissionamount - commissionamount) / 50000)
       ) * 2500 as this_months_commission
from (select t.*,
             sum(commissionamount) over (partition by rowgrouping order by yearmonth) as running_commissionamount
      from t
     ) t

这里唯一真正棘手的部分是计算通过的50,000个阈值的数量。

© www.soinside.com 2019 - 2024. All rights reserved.