Search code examples
t-sqlwindow-functions

t-sql function like "filter" for sum(x) filter(condition) over (partition by


I'm trying to sum a window with a filter. I saw something similar to sum(x) filter(condition) over (partition by...) but it does not seem to work in t-sql, SQL Server 2017.

Essentially, I want to sum the last 5 rows that have a condition on another column.

I've tried sum(case when condition...) over (partition...) and sum(cast(nullif(x))) over (partition...).

I've tried left joining the table with a where condition to filter out the condition.

All of the above will add the last 5 from the starting point of the current row with the condition.

What I want is from the current row. Add the last 5 values above that meet a condition.

Date| Value | Condition | Result
1-1   10      1          
1-2   11      1 
1-3   12      1
1-4   13      1
1-5   14      0
1-6   15      1
1-7   16      0
1-8   17      0      sum(15+13+12+11+10)
1-9   18      1      sum(18+15+13+12+11)
1-10  19      1      sum(19+18+15+13+12)

In the above example the condition I would want would be 1, ignoring the 0 but still having the "window" size be 5 non-0 values.


Solution

  • This can easily be achieved using a correlated sub query:

    First, create and populate sample table (Please save us this step in your future questions):

    DECLARE @T AS TABLE
    (
        [Date] Date, 
        [Value] int, 
        Condition bit
    )
    INSERT INTO @T ([Date], [Value], Condition) VALUES
    ('2019-01-01', 10, 1),
    ('2019-01-02', 11, 1),
    ('2019-01-03', 12, 1),
    ('2019-01-04', 13, 1),
    ('2019-01-05', 14, 0),
    ('2019-01-06', 15, 1),
    ('2019-01-07', 16, 0),
    ('2019-01-08', 17, 0),
    ('2019-01-09', 18, 1),
    ('2019-01-10', 19, 1)
    

    The query:

    SELECT [Date], [Value], Condition,
           (
               SELECT Sum([Value])
               FROM 
               (
                   SELECT TOP 5 [Value] 
                   FROM @T AS t1
                   WHERE Condition = 1
                   AND t1.[Date] <= t0.[Date]
    -- If you want the sum to appear starting from a specific date, unremark the next row
                   --AND t0.[Date] >  '2019-01-07'
                   ORDER BY [Date] DESC                 
               ) As t2
               HAVING COUNT(*) = 5 -- there are at least 5 rows meeting the condition
           ) As Result
    FROM @T As T0
    

    Results:

    Date        Value   Condition   Result
    2019-01-01  10      1           
    2019-01-02  11      1           
    2019-01-03  12      1           
    2019-01-04  13      1           
    2019-01-05  14      0           
    2019-01-06  15      1           61
    2019-01-07  16      0           61
    2019-01-08  17      0           61
    2019-01-09  18      1           69
    2019-01-10  19      1           77