Search code examples
sqlsql-server-2017

SQL Server - SUM Preceding Rows With Condition Linked to Original Row


For each row in the below example data set, the code does a sum of the previous 5 rows when a certain condition is met.

The problem I'm having is the condition needs to reference the original row rating e.g. I need to sum preceding rows only if the rating is within 1 of the current row.

Example data:

DECLARE @tbl TABLE 
             (
                 Team varchar(1),
                 date date, 
                 Rating int, 
                 Score int
             );

INSERT INTO @tbl (Team, Date, Rating, Score)
VALUES
('a', '2020/12/05', '20', '1'),
('a', '2020/12/04', '18', '8'),
('a', '2020/12/03', '21', '3'),
('a', '2020/12/02', '19', '4'),
('a', '2020/12/01', '19', '3');

Current code:

SELECT
    Rating, 
    SUM(CASE WHEN Rating >= (Rating-1) AND  Rating <= (Rating+1) THEN SCORE END) 
        OVER (partition by Team ORDER BY Date ASC ROWS BETWEEN 5 PRECEDING AND 1 PRECEDING) AS SUM
FROM
    @tbl
ORDER BY 
    Date DESC

Output:

    +------------------+------------+------------+
    |  Rating          | Current    | Required   | 
    +------------------+------------+------------+
    | 20               | 18         |     7      |
    | 18               | 10         |     7      |
    | 21               | 7          |     NULL   |
    | 19               | 3          |     3      |
    | 18               | NULL       |     NULL   |
    +------------------+------------+------------+

The problem is this following section of the code is not working as the rating is being assessed on a line by line by line basis.

CASE WHEN Rating >= (Rating-1) AND  Rating <= (Rating+1)

I need it to assess against the rating of the original row (I've looked into Top but that isn't working):

CASE WHEN Rating >= ((SELECT TOP 1 Rating) - 1) AND Rating <= ((SELECT TOP 1 Rating) + 1)

Any help appreciated as always.


Solution

  • What you are describing sounds like a lateral join:

    SELECT t.*, t2.*
    FROM @tbl t OUTER APPLY
         (SELECT SUM(t2.score) as score_5
          FROM (SELECT TOP (5) t2.*
                FROM @tbl t2
                WHERE t2.date < t.date
                ORDER BY t2.date DESC
               ) t2
          WHERE t2.rating BETWEEN t.rating - 1 AND t.rating + 1
         ) t2
    ORDER BY Date DESC