2016-05-23 6 views
0

を照会するには、ヘルプ「プラグ操作で」表Iは、手動で入力された変数(ラベル)指定されたローンの償却スケジュールを作成するには、以下のクエリを持っている:のSQL Server 2012から

DECLARE @PV as Float = -290000 --Loan Amount 
,@FV as float = 0 --Value of the loan at termination 
,@Term as float = 30 --The term of the loan in years 
,@Pay_type as bit = 0 --Identifies the payment as due at the end (0) or the beginning (1) of the period 
,@annual_rate as float = .03375 --The annual rate of interest 
,@payment_frequency as float = 12 --The number of payments in a year 
,@startdate as datetime = '07/31/2016' 
,@rate as float 
,@nper as float 

Set @rate = @annual_rate/@payment_frequency 
Set @nper = @Term * @payment_frequency 

;WITH 
Nbrs_3(n) AS (SELECT 1 UNION SELECT 0), 
Nbrs_2(n) AS (SELECT 1 FROM Nbrs_3 n1 CROSS JOIN Nbrs_3 n2), 
Nbrs_1(n) AS (SELECT 1 FROM Nbrs_2 n1 CROSS JOIN Nbrs_2 n2), 
Nbrs_0(n) AS (SELECT 1 FROM Nbrs_1 n1 CROSS JOIN Nbrs_1 n2), 
Nbrs (n) AS (SELECT 1 FROM Nbrs_0 n1 CROSS JOIN Nbrs_0 n2) 
SELECT n as [Period] 
,CASE @payment_frequency 
    WHEN 13 THEN DATEADD(week,4*n,@startdate) 
    WHEN 26 THEN DATEADD(week,2*n,@startdate) 
    WHEN 52 THEN DATEADD(week,n,@startdate) 
    ELSE DATEADD(M,12*n/@payment_frequency,@startdate) END as [Due Date] 
,-wct.PV(@rate,@nper-(n- 1) 
,wct.PMT(@rate,@nper,@PV,@FV,@pay_type),@FV,@pay_type) as [Starting Balance] 
,wct.PMT(@rate,@nper,@PV,@FV,@pay_type) as [Payment] 
,wct.IPMT(@rate,n,@nper,@PV,@FV,@pay_type) as [Interest Payment] 
,wct.PPMT(@rate,n,@nper,@PV,@FV,@pay_type) as [Principal Payment] 
,-wct.PV(@rate,@nper-n,wct.PMT(@rate,@nper,@PV,@FV,@pay_type),@FV,@pay_type) as [Ending Balance] 
FROM (SELECT ROW_NUMBER() OVER (ORDER BY n) 
     FROM Nbrs) D(n) 
WHERE n <= @nper 

私がやろうとしていますどのような既に変数(PV、期間、レートなど)に値が割り当てられているローンのテーブル(dbo.Loans)からこのクエリを取得しています。私はこれをテーブル値関数にすることが最善であると考えていますが、関数についてもあまり経験はなく、適切なコーディングを行うことができません。

+0

ここに非常に注意してください。これは金融アプリケーションのように見え、すべてを浮動体と定義しています。浮動小数点数は、おおよそのデータ型であるため、精度を失う可能性があります。浮動小数点数での分割は正確に格納できない値で終わるので、実際に支払いを計算するようなことをすることで現れ始めます。数値データ型を使用する方がよいでしょう。もちろん、年間の支払い回数などの場合、intははるかに意味があります。 –

答えて

0

すべての必要な入力パラメータを持つTable-Valued User-Defined Functionにロジックを埋め込み、最後のSELECTに対応する構造を持つテーブルを返すことができます。以下のような何か:

CREATE FUNCTION dbo.ufnGetAmortizationSchedule 
(
    @LoanId INT 
    -- other input paramters may come here 
) 
RETURNS @sheduleTable TABLE 
(
    DueDate DATE, 
    StartingBalance NUMERIC(18, 4), -- as already mentioned, fixed-point numbers should be used 
    Payment NUMERIC(18, 4) 
    -- other result columns come here 
) 
AS 
BEGIN 
    DECLARE @PV as Float --Loan Amount 
    ,@FV as float --Value of the loan at termination 
    ,@Term as float --The term of the loan in years 
    ,@Pay_type as bit --Identifies the payment as due at the end (0) or the beginning (1) of the period 
    ,@annual_rate as float --The annual rate of interest 
    ,@payment_frequency as float --The number of payments in a year 
    ,@startdate as datetime 
    ,@rate as float 
    ,@nper as float 

    SELECT @PV = PV, @FV = FV, @Term = Term 
     -- other variable assignment here 
    FROM dbo.Loan 
    WHERE LoanId = @LoadId 

    Set @rate = @annual_rate/@payment_frequency 
    Set @nper = @Term * @payment_frequency 

    ;WITH 
    Nbrs_3(n) AS (SELECT 1 UNION SELECT 0), 
    Nbrs_2(n) AS (SELECT 1 FROM Nbrs_3 n1 CROSS JOIN Nbrs_3 n2), 
    Nbrs_1(n) AS (SELECT 1 FROM Nbrs_2 n1 CROSS JOIN Nbrs_2 n2), 
    Nbrs_0(n) AS (SELECT 1 FROM Nbrs_1 n1 CROSS JOIN Nbrs_1 n2), 
    Nbrs (n) AS (SELECT 1 FROM Nbrs_0 n1 CROSS JOIN Nbrs_0 n2) 

    -- inserting data into the result table 
    INSERT INTO @sheduleTable 
    (DueDate, StartingBalance, Payment /* other columns */) 
    SELECT n as [Period] 
    ,CASE @payment_frequency 
     WHEN 13 THEN DATEADD(week,4*n,@startdate) 
     WHEN 26 THEN DATEADD(week,2*n,@startdate) 
     WHEN 52 THEN DATEADD(week,n,@startdate) 
     ELSE DATEADD(M,12*n/@payment_frequency,@startdate) END as [Due Date] 
    ,-wct.PV(@rate,@nper-(n- 1) 
    ,wct.PMT(@rate,@nper,@PV,@FV,@pay_type),@FV,@pay_type) as [Starting Balance] 
    ,wct.PMT(@rate,@nper,@PV,@FV,@pay_type) as [Payment] 
    ,wct.IPMT(@rate,n,@nper,@PV,@FV,@pay_type) as [Interest Payment] 
    ,wct.PPMT(@rate,n,@nper,@PV,@FV,@pay_type) as [Principal Payment] 
    ,-wct.PV(@rate,@nper-n,wct.PMT(@rate,@nper,@PV,@FV,@pay_type),@FV,@pay_type) as [Ending Balance] 
    FROM (SELECT ROW_NUMBER() OVER (ORDER BY n) 
      FROM Nbrs) D(n) 
    WHERE n <= @nper 
END 
GO 
+0

これはマルチステートメントのテーブル値関数です。これらのパフォーマンスは恐ろしいものです。スカラー関数より悪い。これは単一のステートメントでなければなりません。 –

+0

それは正しいです。私の経験から、このような計算は、はるかに高速であるため、C#、Java、C++などの言語で実装する必要があります。 – Alexei

0

ここでは、インラインテーブル値関数としてこれを行うことができます方法です。しかし問題はスカラー関数wctがここにあるようです。それはあなたのパフォーマンスを損なうでしょう。また、クエリに空白を追加したので、読みやすくなりました。

create function AmoritzationSchedule 
(
    @PV as Float = -290000 --Loan Amount 
    ,@FV as float = 0 --Value of the loan at termination 
    ,@Term as float = 30 --The term of the loan in years 
    ,@Pay_type as bit = 0 --Identifies the payment as due at the end (0) or the beginning (1) of the period 
    ,@annual_rate as float = .03375 --The annual rate of interest 
    ,@payment_frequency as float = 12 --The number of payments in a year 
    ,@startdate as datetime = '07/31/2016' 
)RETURNS TABLE as RETURN 

WITH 
Nbrs_3(n) AS (SELECT 1 UNION SELECT 0), 
Nbrs_2(n) AS (SELECT 1 FROM Nbrs_3 n1 CROSS JOIN Nbrs_3 n2), 
Nbrs_1(n) AS (SELECT 1 FROM Nbrs_2 n1 CROSS JOIN Nbrs_2 n2), 
Nbrs_0(n) AS (SELECT 1 FROM Nbrs_1 n1 CROSS JOIN Nbrs_1 n2), 
Nbrs (n) AS (SELECT 1 FROM Nbrs_0 n1 CROSS JOIN Nbrs_0 n2) 
SELECT n as [Period] 
    ,CASE @payment_frequency 
     WHEN 13 THEN DATEADD(week, 4 * n, @startdate) 
     WHEN 26 THEN DATEADD(week, 2 * n, @startdate) 
     WHEN 52 THEN DATEADD(week, n, @startdate) 
     ELSE DATEADD(Month, 12 * n/@payment_frequency, @startdate) 
    END as [Due Date] 
    , - wct.PV((@annual_rate/@payment_frequency), (@Term * @payment_frequency) - (n - 1), wct.PMT((@annual_rate/@payment_frequency), (@Term * @payment_frequency), @PV, @FV, @pay_type), @FV, @pay_type) as [Starting Balance] 
    , wct.PMT((@annual_rate/@payment_frequency), (@Term * @payment_frequency), @PV, @FV, @pay_type) as [Payment] 
    , wct.IPMT((@annual_rate/@payment_frequency), n, (@Term * @payment_frequency), @PV, @FV, @pay_type) as [Interest Payment] 
    , wct.PPMT((@annual_rate/@payment_frequency), n, (@Term * @payment_frequency), @PV, @FV, @pay_type) as [Principal Payment] 
    , - wct.PV((@annual_rate/@payment_frequency), (@Term * @payment_frequency) - n, wct.PMT((@annual_rate/@payment_frequency), (@Term * @payment_frequency), @PV, @FV, @pay_type), @FV, @pay_type) as [Ending Balance] 
FROM (SELECT ROW_NUMBER() OVER (ORDER BY n) 
     FROM Nbrs) D(n) 
WHERE n <= (@Term * @payment_frequency) 
0

私は実際に私の問題を解決するために、このを思い付くことができました、アドバイスありがとうございました:

CREATE TABLE #Loans 
(
LoanNumber nvarchar(50) 
,PV DECIMAL(18,8) --Loan Amount 
,FV DECIMAL(18,8) --Value of the loan at termination 
,Term DECIMAL(18,8) --The term of the loan in years 
,Pay_type BIT --Identifies the payment as due at the end (0) or the beginning (1) of the period 
,annual_rate DECIMAL(18,8) --The annual rate of interest 
,payment_frequency DECIMAL(18,8) --The number of payments in a year 
,FirstPayment DATETIME 
,rate AS (annual_rate/payment_frequency) 
,nper AS (Term * payment_frequency) 
); 

INSERT INTO #Loans 
(
LoanNumber 
,PV 
,FV 
,Term 
,Pay_type 
,annual_rate 
,payment_frequency 
,FirstPayment 
) 
select top 5 
a.LoanNumber 
,a.PV 
,0 as FV 
,a.NewLoanTerm30yrFxd/12 as Term 
,0 as Pay_Type 
,a.EstNewRate30yrFxd/100 as annual_rate 
,12 as Payment_Frequency 
,DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+2,0)) as FirstPayment 
from #LoanPool a 
; 


WITH 
Nbrs_3(n) AS (SELECT 1 UNION SELECT 0), 
Nbrs_2(n) AS (SELECT 1 FROM Nbrs_3 n1 CROSS JOIN Nbrs_3 n2), 
Nbrs_1(n) AS (SELECT 1 FROM Nbrs_2 n1 CROSS JOIN Nbrs_2 n2), 
Nbrs_0(n) AS (SELECT 1 FROM Nbrs_1 n1 CROSS JOIN Nbrs_1 n2), 
Nbrs (n) AS (SELECT 1 FROM Nbrs_0 n1 CROSS JOIN Nbrs_0 n2), 
RowNbrs (n) AS (SELECT ROW_NUMBER() OVER (ORDER BY n) FROM Nbrs) 

SELECT 
a.LoanNumber 
,D.n as [Period] 
,CASE a.payment_frequency 
    WHEN 13 THEN DATEADD(week,4*n,a.FirstPayment) 
    WHEN 26 THEN DATEADD(week,2*n,a.FirstPayment) 
    WHEN 52 THEN DATEADD(week,n,a.FirstPayment) 
    ELSE DATEADD(M,12*n/a.payment_frequency,a.FirstPayment) 
END as [Due Date] 
,-wct.PV(a.rate,a.nper-(n-1),wct.PMT(a.rate,a.nper,a.PV,a.FV,a.pay_type),a.FV,a.pay_type) AS [Starting Balance] 
,wct.PMT(a.rate,a.nper,a.PV,a.FV,a.pay_type) AS [Payment] 
,wct.IPMT(a.rate,n,a.nper,a.PV,a.FV,a.pay_type) AS [Interest Payment] 
,wct.PPMT(a.rate,n,a.nper,a.PV,a.FV,a.pay_type) AS [Principal Payment] 
,-wct.PV(a.rate,a.nper-n,wct.PMT(a.rate,a.nper,a.PV,a.FV,a.pay_type),a.FV,a.pay_type) AS [Ending Balance] 
into #Amortization 

FROM 
RowNbrs AS D 
    CROSS APPLY #Loans AS a 
WHERE 
n <= a.nper 
order by a.LoanNumber, [Due Date]