Reputation: 1401
How can I use WHERE
clause to filter in the OVER
clause?
i.e. from the following data
LoanID | Principal | Tenor | AmortizingPrincipal
----------------------------------------
1 20000 1 5000
1 20000 2 5000
1 20000 3 5000
1 20000 4 5000
I need a fourth virtual column with the Balance Principal in each Tenor like the following:
LoanID | Principal | Tenor | AmortizingPrincipal | BalancePrinicpal
-----------------------------------------------------------
1 20000 1 5000 20000
1 20000 2 5000 15000
1 20000 3 5000 10000
1 20000 4 5000 5000
Something like this:
SELECT
BalancePrincipal = Principal - SUM(AmortizingPrincipal) OVER(PARTITION BY LoanID WHERE Tenor < this row's tenor)
UPDATE:
The following query gives me the desired result:
SELECT L1.* ,BalancePrincipal = AL1.Principal - ISNULL(Cumulative.AmortizingSum,0) FROM Loan L1 CROSS APPLY ( SELECT AmortizingSum = SUM(AmortizingPrincipal) FROM Loan L2 WHERE L1.LoanID = L2.LoanID AND L1.Tenor > L2.Tenor ) Cumulative
Can it be bettered?
Upvotes: 15
Views: 38288
Reputation: 9170
For the sample posted, it doesn't look like a filter is needed:
SELECT LoanID, Principal, Tenor, AmortizingPrincipal
,SUM(AmortizingPrincipal) OVER(PARTITION BY LoanID ORDER BY Tenor Desc) AS BalancePrincipal
FROM loan
ORDER BY LoanID, Principal, Tenor
UPDATE:
Seems Sql Server 2008 does not have the windowing clause? I didn't even think you could create an analytic function without a windowing clause. The above sql was run on Oracle and Postgres without issue. By default the window clause is UNBOUNDED PRECEDING AND CURRENT ROW (from - to). But you could change the order and go from CURRENT ROW to UNBOUNDED FOLLOWING.
UPDATE2:
So I puzzled: what meaning would a (cumulative) SUM have in an analytic function if you are unable to order the rows within the partition? Is there an implicit ordering? I can change the window (below) and get the same result, but must provide the ORDER BY (in Oracle and Postgres). I can't see how the analytic SUM would have any meaning without the ORDER BY.
SELECT LoanID, Principal, Tenor, AmortizingPrincipal
,SUM(AmortizingPrincipal) OVER(PARTITION BY LoanID ORDER BY tenor
RANGE BETWEEN CURRENT ROW
AND UNBOUNDED FOLLOWING) AS BalancePrincipal
FROM loan
ORDER BY LoanID, Principal, Tenor
Upvotes: 0
Reputation: 239824
If you're using SQL Server 2012, you'd be looking to specify ROWS
/RANGE
in your OVER
:
Further limits the rows within the partition by specifying start and end points within the partition. This is done by specifying a range of rows with respect to the current row either by logical association or physical association. Physical association is achieved by using the ROWS clause.
Other database systems may have similar features. This feature is new in the 2012 version of SQL Server.
Upvotes: 6