SQL Server 2012根据优先级和百分比

时间:2017-02-07 03:00:34

标签: sql tsql sql-server-2012

希望你能提供帮助。

这是我的表:

Declare @AmtToDistribute float = 500.00

DECLARE @TestTable TABLE(TempID INT IDENTITY(1, 1) NOT NULL,
                         VicID INT ,
                         VicOrderedAmt MONEY,
                         RemainingBalance MONEY,
                         DistPriority INT,
                         DistPercentOf DECIMAL(5, 2),
                         DistributionAmt MONEY
                        );

INSERT INTO @TestTable ([VicID], [VicOrderedAmt], [RemainingBalance], [DistPriority], [DistPercentOf], [DistributionAmt])
VALUES (2318, 5.00, 5.00, 1, 60.00, 0),
       (2319, 50.00, 25, 1, 40.00, 0),
       (2320, 500.00, 500.0, 2, 33.00, 0),
       (2321, 500.00, 500.0, 2, 33.00, 0),
       (2322, 500.00, 500.0, 2, 34.00, 0);

SELECT * FROM @TestTable;

Sample table structure

我试图找到一个查询,允许我向第一优先级的每一行分配一个美元金额,直到这些值达到零,然后跳到下一个优先级,直到这些值达到零。问题在于,必须根据DistPercentOf列分配美元金额。例如,优先级为1的2行首先分割金额,VicID获得金额的60%,直到满足VicOrderedAmt,然后第二个VicId获得金额的40%。达到优先级1金额后,请转到优先级2.

我已经看过几个帖子,但是他们只处理一个优先级,我需要先支付一个优先级,然后再转到下一个。

提前致谢。

1 个答案:

答案 0 :(得分:0)

尝试这样的事情:

Declare @AmtToDistribute MONEY = 500.00

DECLARE @TestTable TABLE (
    TempID                   INT IDENTITY(1, 1) NOT NULL,
    VicID                    INT ,
    VicOrderedAmt            MONEY,
    RemainingBalance         MONEY,
    DistPriority             INT,
    DistPercentOf            DECIMAL(5, 2),
    DistributionAmt          MONEY
);

INSERT INTO @TestTable
    (VicID, VicOrderedAmt, RemainingBalance, DistPriority, DistPercentOf, DistributionAmt)
    VALUES (2318, 5.00, 5.00, 1, 60.00, 0)
    , (2319, 50.00, 25, 1, 40.00, 0)
    , (2320, 500.00, 500.0, 2, 33.00, 0)
    , (2321, 500.00, 500.0, 2, 33.00, 0)
    , (2322, 500.00, 500.0, 2, 34.00, 0);

WHILE 1=1 BEGIN
    UPDATE y 
    SET y.DistributionAmt=y.DistributionAmt+y.CurrentDistributedAmt, 
        y.RemainingBalance=y.RemainingBalance-y.CurrentDistributedAmt, 
        @AmtToDistribute=@AmtToDistribute-CurrentDistributedAmt
    FROM (
        SELECT *, 
            CASE WHEN @AmtToDistribute<RemainingBalanceForCurrentPriority
                THEN CASE 
                    WHEN RemainingBalance<@AmtToDistribute*x.DistPercentOf/TotalDistPercent 
                    THEN x.RemainingBalance
                    ELSE @AmtToDistribute*x.DistPercentOf/TotalDistPercent 
                END
                ELSE x.RemainingBalance
            END AS CurrentDistributedAmt
        FROM (
            SELECT *, SUM(RemainingBalance) OVER () AS RemainingBalanceForCurrentPriority,
                SUM(DistPercentOf) OVER () AS TotalDistPercent
            FROM @TestTable WHERE DistPriority=(
                SELECT MIN(DistPriority) FROM @TestTable 
                WHERE RemainingBalance>0
            ) AND RemainingBalance>0
        ) x
    ) y

    IF @AmtToDistribute=0 BREAK
    IF NOT EXISTS (SELECT * FROM @TestTable WHERE RemainingBalance>0) BREAK
END

select * From @TestTable;

为避免舍入错误,请确保@AmtToDistribute与DistributionAmt列具有相同的数据类型。

稍后编辑(2017年2月12日):

我对上面代码中的UPDATE语句做了一些更正。

此外,考虑使用NUMERIC(19,4)而不是MONEY,因为它具有更好的舍入行为。有关详细信息,请参阅Should you choose the MONEY or DECIMAL(x,y) datatypes in SQL Server?