Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Вземете актуализирана стойност на предишния ред с помощта на LAG, без да използвате рекурсивен CTE

Производителността тук страда от рекурсивно CTE. CTE сам по себе си е просто синтактична захар.

Само за тези конкретни примерни данни това работи без рекурсия:

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;

Това може да помогне за оценка на производителността, но няма да успее, ако в който и да е блок общо Debit надвишават общо Credit с. Ако BlockTotal е отрицателен, тогава той трябва да бъде обединен с един или няколко следващи блока и това не може да стане без итерация или рекурсия.

В реалния живот бих изхвърлил CTE3 във временна таблица и бих преминал през нея, обединявайки блокове, докато няма повече отрицателни BlockTotal с.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. System.Data.SqlTypes.SqlTypeException:препълване на SqlDateTime

  2. Преместване на системни бази данни в клъстера за отказване на SQL Server

  3. създаване на агрегации на подгрупи в sql въз основа на стойност на колона

  4. Може ли SQL Server Pivot, без да знае получените имена на колони?

  5. Изходният параметър на съхранена процедура връща @Value