Les performances ici souffrent de récursif CTE. Le CTE en lui-même n'est que du sucre syntaxique.
Juste pour cet exemple de données particulier, cela fonctionne sans récursivité :
Declare @Tbl as Table(SNO Int,Credit Money,Debit Money,PaidDate Date)
Insert into @Tbl
SELECT * FROM (VALUES (1,0,12,'7Jan16'), (2,10,0,'6Jan16'), (3,15,0,'5Jan16'), (4,0,5,'4Jan16'), (5,0,3,'3Jan16'), (6,0,2,'2Jan16'), (7,20,0,'1Jan16')) AS X(SNO,Credit,Debit,PaidDate);
With CTE1 As (
Select *
, CASE WHEN Credit > 0 THEN LEAD(1 - SIGN(Credit), 1, 1) OVER (ORDER BY SNO) ELSE 0 END As LastCrPerBlock
From @Tbl
), CTE2 As (
Select *
, SUM(LastCrPerBlock) OVER (ORDER BY SNO DESC ROWS UNBOUNDED PRECEDING) As BlockNumber
From CTE1
), CTE3 As (
Select *
, SUM(Credit - Debit) OVER (PARTITION BY BlockNumber) As BlockTotal
, SUM(Credit - Debit) OVER (PARTITION BY BlockNumber ORDER BY SNO ROWS UNBOUNDED PRECEDING) As BlockRunningTotal
From CTE2
)
Select SNO, Credit, Debit
, CASE WHEN BlockRunningTotal < 0 THEN -BlockRunningTotal ELSE 0 END As TotalDebit
, CASE WHEN BlockRunningTotal > 0 THEN CASE WHEN Credit < BlockRunningTotal THEN Credit ELSE BlockRunningTotal END ELSE 0 END As Amount
, PaidDate
From CTE3
Order By SNO;
Cela peut aider à évaluer les performances, mais cela échouera si dans n'importe quel bloc total de Debit
s dépasse le total de Credit
s. Si BlockTotal
est négatif alors il doit être fusionné avec un ou plusieurs blocs suivants et cela ne peut se faire sans itération ni récursivité.
Dans la vraie vie, je viderais CTE3 dans une table temporaire et la parcourrais en fusionnant des blocs jusqu'à ce qu'il n'y ait plus de BlockTotal
négatif s.