Эффективность SQL-курсора для запуска финансового расчета - PullRequest
0 голосов
/ 14 марта 2019

Я написал довольно большую хранимую процедуру для выполнения некоторых вычислений, используя несколько разных наборов данных. В настоящее время он использует курсор для просмотра результатов и выполнения некоторых вычислений. Затем он сохраняет эти вычисления «предыдущих строк» ​​и затем использует их на следующей итерации. Я читал, чтобы избежать курсоров, когда это возможно для производительности. Я хочу, чтобы это масштабировалось настолько хорошо, насколько это возможно, и просто хотел получить какие-либо предложения, если это возможно. Я играл с мыслью о том, что функция LAG может помочь, но мне не повезло. Я использую MS SQL, размещенный в Azure. Вот текущая процедура:

CREATE Procedure [dbo].[spCreateAmoritzation]
@AccountNumber varchar(50)
AS

SET NOCOUNT ON;

BEGIN TRY  
    DECLARE @principalRemaining DECIMAL(10,2);
    DECLARE @AmtFinanced decimal(10,2);
    DECLARE @APR decimal(27,25);
    DECLARE @ContractDate datetime;
    DECLARE @PrincipalBalance decimal;
    SET @PrincipalBalance = 5000;

    SELECT Top 1 @AccountNumber = AccountNumber, 
                 @AmtFinanced = AmtFinanced, 
                @APR = APR, 
                @ContractDate = ContractDate
    FROM Account s
    WHERE AccountNumber = @AccountNumber


    DECLARE @interestRemaining DECIMAL(10,2);
    DECLARE @principalCollected DECIMAL(10,2);
    DECLARE @interestPerDiem DECIMAL(10,9);

    SET @interestRemaining = 0;
    SET @principalCollected = 0;
    SET @principalRemaining = @AmtFinanced;


    DECLARE @RowCount INT;

    IF @APR > 1
           SET @APR = @APR/100.00;

    DECLARE th_cursor CURSOR LOCAL FAST_FORWARD  FOR 
    SELECT EffectiveDate, Principal,Type
    FROM Transactions
    WHERE AccountID = @AccountNumber
    ORDER BY Id ASC

    OPEN th_cursor


    DECLARE @EffectiveDate datetime;
    DECLARE @Principal DECIMAL(18,2);
    DECLARE @Type varchaR(50);
    DECLARE @interestEarned decimal(10,2);


    FETCH NEXT FROM th_cursor   
    INTO @EffectiveDate, @Principal ,@Type

     IF @@FETCH_STATUS <> 0 
     BEGIN
        CLOSE th_cursor;  
        DEALLOCATE th_cursor;  
           RETURN    
        END


    DECLARE @Table TABLE (
    AccountNumber varchar(50),
    PaymentDate datetime,
    Payment decimal(18,2),
    Type varchar(30),
    InterestPerDiem decimal(10,9) null,
    InterestEarned decimal(10,2) null,
    InterestRemaining decimal(10,2) null,
    PrincipalCollected decimal(18,2) null,
    PrincipalRemaining decimal(18,2)
    )

        INSERT INTO @Table 
            (AccountNumber,Payment, PaymentDate,  Type, PrincipalRemaining )
            VALUES 
            (@AccountNumber, 0, @ContractDate, 'PAYMENT', @principalRemaining) 



        WHILE @@FETCH_STATUS = 0  
        BEGIN  
            SET @interestPerDiem = (@APR/365)  * @principalRemaining  
            SET @interestEarned = ((DATEDIFF(DAY,@ContractDate, @EffectiveDate) * @interestPerDiem) + @interestRemaining)
            IF (@Type = 'PAYMENT')

            BEGIN

                    IF (@interestEarned - @Principal > 0) 
                        SET @interestRemaining = @interestEarned - @Principal;
                    ELSE
                        SET @interestRemaining = 0


                    IF(@interestEarned - @Principal > 0)
                        SET @principalCollected = 0
                    ELSE
                       SET @principalCollected= @Principal - @interestEarned


                    SET @principalRemaining = @principalRemaining - @principalCollected
            END

            IF (@Type = 'PRNCRADJ')
                BEGIN 
                    SET @principalRemaining = @principalRemaining - @Principal
                    SET @interestPerDiem = NULL
                    set @interestEarned = NULL
                    set @principalCollected = NULL
            END

            IF (@Type = 'PRNDRADJ')
                BEGIN 
                    SET @principalRemaining = @principalRemaining+ @Principal
                    SET @interestPerDiem = NULL
                    set @interestEarned = NULL
                    set @principalCollected = NULL
            END


            INSERT INTO @Table 
            (AccountNumber, PaymentDate, Payment, Type, InterestPerDiem, InterestRemaining, InterestEarned, PrincipalCollected, PrincipalRemaining )
            VALUES 
            (@AccountNumber, @EffectiveDate, @Principal, @Type, @interestPerDiem, @interestRemaining, @interestEarned, @principalCollected, @principalRemaining) 

            SET @ContractDate = @EffectiveDate


             FETCH NEXT FROM th_cursor INTO @EffectiveDate, @Principal ,@Type  
        END   


    CLOSE th_cursor;  
    DEALLOCATE th_cursor;  

        INSERT INTO Results
        (AccountNumber, PaymentDate, Payment, Type, InterestPerDiem, InterestRemaining, InterestEarned, PrincipalCollected, PrincipalRemaining )
        SELECT * from @Table;

        UPDATE Calculator
        SET Variance = @principalRemaining, LastCalculated = GetDate()
        WHERE AccountID = @AccountNumber;

END TRY  
BEGIN CATCH  
    return
END CATCH


GO

Вот пример данных из таблицы транзакций:

AccountID   EffectiveDate   Principal   Type
12345   10/3/2013   450.00  PAYMENT
12345   10/30/2013  419.34  PAYMENT
12345   12/2/2013   419.34  PAYMENT
12345   1/17/2014   414.00  PAYMENT
12345   2/12/2014   420.00  PAYMENT

Вот пример выходных данных из таблицы результатов:

AccountID   Payment Type    InterestPerDiem InterestRemaining   InterestEarned  PrincipalCollected  PrincipalRemaining
12345   0.00    PAYMENT NULL    NULL    NULL    NULL    10875.82
12345   244.19  PAYMENT 2.976697036 119.07  0.00    125.12  10750.70
12345   244.19  PAYMENT 2.942451863 85.33   0.00    158.86  10591.84
12345   244.19  PAYMENT 2.898972099 86.97   0.00    157.22  10434.62
12345   244.19  PAYMENT 2.855941200 114.24  0.00    129.95  10304.67

Результатом этой функции является то, что она захватит учетную запись и получит некоторую базовую информацию, такую ​​как APR, сумма финансирования и дата контракта.

Затем будет выполнен цикл по списку транзакций для этой учетной записи, который будет включать даты и платежи. Поскольку он проходит по каждой строке транзакций, он будет рассчитывать проценты и т. Д., Используя APR и несколько других метрик. В конечном итоге этот набор результатов будет записан в таблицу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...