sql >> Database teknologi >  >> RDS >> Sqlserver

Få forrige række opdateret værdi ved hjælp af LAG Uden at bruge rekursiv CTE

Ydeevne her lider under rekursiv CTE. CTE i sig selv er bare syntaktisk sukker.

Bare for denne specifikke eksempeldata virker dette uden gentagelser:

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;

Dette kan hjælpe med at evaluere ydeevnen, men det vil mislykkes, hvis i en bloktotal Debit s overstiger det samlede antal Credit s. Hvis BlockTotal er negativ, skal den flettes med en eller flere efterfølgende blokke, og det kan ikke gøres uden iteration eller rekursion.

I det virkelige liv ville jeg dumpe CTE3 ind i den midlertidige tabel og cykle over dens fletteblokke, indtil der ikke er flere negative BlockTotal s.



  1. SQL time i gennemsnit på 24 timer

  2. Sådan fjerner du krav med ClaimStatus =1 baseret på aktivitetsdato. SQL Server 2012

  3. Postgresql base64-kode

  4. 3-cifret valutakode til valutasymbol