2017-02-07 6 views
1

Надеюсь, вы сможете помочь.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

Я пытаюсь найти запрос, который позволяет мне распределить сумму в долларах каждой строке в 1-й приоритет, пока эти значения не достигнет нуля и затем переходите к следующему приоритету, пока эти значения не достигнут нуля. Улов заключается в том, что сумма доллара должна распределяться на основе столбца DistPercentOf. Например, 2 строки в приоритете 1 разделяют сумму сначала, когда VicID получает 60% от суммы до тех пор, пока VicOrderedAmt не будет удовлетворен, тогда второй VicId получит 40% от суммы. После того, как были выполнены приоритеты 1, перейдите к Приоритету 2.

Я видел несколько сообщений, но они касаются только одного приоритета, и мне нужно заплатить один приоритет, прежде чем переходить к следующему.

Заранее спасибо.

+0

Я думаю, что это работа для прикладного уровня, а не для базы данных. – cha

+0

Непонятно с вопросом. Для первой записи вы хотите обновить DistributionAmt до 60% от 500, то есть 300, а VicOrderedAmt - 5 , следовательно, обновление до 5? Аналогично для 2-й записи 50 и 3-й записи 33% (500-5-50) = 146,85? –

+0

@RajeshBhat, это правильно. cha, теперь у меня это как курсор, но он попадает в цикл в один момент, поэтому он будет работать на БД, просто нужно, чтобы это было правильно, чтобы заставить его работать. – qwerty1906

ответ

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, 
     @[email protected] 
    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.

Позже редактировать (12 февраля 2017):

Я сделал несколько исправлений в заявлении UPDATE в приведенном выше коде.

Кроме того, рассмотрите возможность использования NUMERIC (19,4) вместо MONEY, поскольку он имеет лучшее поведение округления. См. Should you choose the MONEY or DECIMAL(x,y) datatypes in SQL Server? для получения дополнительной информации.

+0

Спасибо, очень близко. Используйте это, чтобы засеять таблицу и AmtToDistribute, и она переходит в бесконечный цикл, потому что она застряла на .0001. ** Заявить @AmtToDistribute MONEY = 50.00 ** **, (2319, 50.00, 50, 1, 40.00, 0) ** – qwerty1906

+0

Я внесла несколько исправлений в код выше. –