Я написал довольно большую хранимую процедуру для выполнения некоторых вычислений, используя несколько разных наборов данных. В настоящее время он использует курсор для просмотра результатов и выполнения некоторых вычислений. Затем он сохраняет эти вычисления «предыдущих строк» и затем использует их на следующей итерации. Я читал, чтобы избежать курсоров, когда это возможно для производительности. Я хочу, чтобы это масштабировалось настолько хорошо, насколько это возможно, и просто хотел получить какие-либо предложения, если это возможно. Я играл с мыслью о том, что функция 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 и несколько других метрик. В конечном итоге этот набор результатов будет записан в таблицу.