SQL游标运行财务计算的效率

时间:2019-03-14 13:12:04

标签: sql performance stored-procedures

我编写了一个相当大的存储过程,以使用几个不同的数据集运行一些计算。当前,它使用光标在结果之间循环并运行一些计算。然后,它存储这些“先前行”计算,然后在下一次迭代中使用这些计算。我已阅读,以尽可能避免出现游标以提高性能。我希望它能尽可能地扩展,并且只需要任何建议。我一直在想也许LAG功能可以在这里提供帮助,但没有任何运气。我正在使用Azure中托管的MS SQL。这是当前过程:

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和其他一些指标来计算利息。最终,该计算结果集将被写入表中。

0 个答案:

没有答案