ito
ito

Reputation: 157

Decremental value with SQL Server LAG function not return the expected value after the 2nd row

I'm trying to return a decremental column in SQL SELECT Statement using LAG function. The result until the 2nd row is the expected, but for 3rd the result is different.

The original dataset:

AvailableId Date Hour Consumed Available
158632 2022-05-03 08 4 50
158632 2022-05-03 09 18 50
158632 2022-05-03 10 28 50

The expected result is more one column with Remaining decremental (Available - Consumed):

AvailableId Date Hour Consumed Available Remaining
158632 2022-05-03 08 4 50 50
158632 2022-05-03 09 18 50 46
158632 2022-05-03 10 28 50 28

I tried with the query:

select 
    AvailableId
    ,Date
    ,Hour
    ,Consumed
    ,Available
    ,case 
            when row_number() over(partition by AvailableId order by Date asc, Hour asc) = 1 then Available
            when row_number() over(partition by AvailableId order by Date asc, Hour asc) = 2 then (Available - lag( Consumed ) over(partition by AvailableId order by Date asc, Hour asc))
            else ((Available- lag( Consumed ) over(partition by AvailableId order by Date asc, Hour asc)) - lag( Consumed ) over(partition by AvailableId order by Date asc, Hour asc))
    end as Remaining
from 
    #temp

But the result was:

AvailableId Date Hour Consumed Available Remaining
158632 2022-05-03 08 4 50 50
158632 2022-05-03 09 18 50 46
158632 2022-05-03 10 28 50 14

After the Second Row the decrement not work (46 - 18), this works fine only the AvailableId have two lines. Someone knows how to return the expected result for 3rd, 4th, until N rows in this case?

The DDL:

create table #temp(
    [AvailableId] int not null
    ,[Date] date not null
    ,[Hour] int not null
    ,[Consumed] int null
    ,[Available] int null
)
go
insert into #temp values
    (158632,'2022-03-05',08, 4, 50),
    (158632,'2022-03-05',09, 18, 50),
    (158632,'2022-03-05',10, 28, 50)
go

Upvotes: 0

Views: 83

Answers (1)

ito
ito

Reputation: 157

I follow the tip of #Larnu and I could return the expected result using cumulative sum:

with cte as(
    select 
        t1.AvailableId
        ,t1.Date
        ,t1.Hour
        ,t1.Consumed
        ,t1.Available
        ,sum(t1.Consumed) over(partition by t1.AvailableId order by t1.Date asc, t1.Hour asc) as CumSum
    from 
        #temp as t1
)
select 
    t2.AvailableId
    ,t2.Date
    ,t2.Hour
    ,t2.Consumed
    ,t2.Available
    ,case
        when lag(t2.CumSum) over(partition by t2.AvailableId order by t2.Date asc, t2.Hour asc) is null then t2.Available
        else t2.Available - lag(t2.CumSum) over(partition by t2.AvailableId order by t2.Date asc, t2.Hour asc)
    end as Consumed
from
    cte as t2

Thank you @Larnu!

Upvotes: 1

Related Questions