Search code examples
sqlsql-serversql-server-2019

Replace NULL value with previous not null one within given partition


How to calculate new column where NULL values from Number column will be replaced with previous not null one? Not NULL ones shall stay untouched. All within partition of Customer.

+----------+------------+--------+
| Customer |    Date    | Number |
+----------+------------+--------+
| A        | 2016-01-01 | 9,00   |
| A        | 2020-01-01 | NULL   |
| A        | 2020-01-15 | 10,00  |
| A        | 2020-02-01 | NULL   |
| A        | 2020-03-01 | NULL   |
| A        | 2020-03-15 | 11,00  |
| A        | 2020-04-01 | NULL   |
| B        | 2016-01-01 | 9,00   |
| B        | 2020-01-01 | NULL   |
| B        | 2020-01-15 | 10,00  |
| B        | 2020-02-01 | NULL   |
| B        | 2020-03-01 | NULL   |
| B        | 2020-03-15 | 11,00  |
| B        | 2020-04-01 | NULL   |
+----------+------------+--------+

Assumptions:

  • input data is ORDER BY Customer, Date, same is expected for the output
  • the first row (oldest one) for each Customer will always have Number different from NULL

Solution

  • This would be easier if SQL Server supported lag(ignore nulls). But it doesn't. You can define groups by doing a cumulative count of the rows with values and then spreading those values:

    select t.*,
           max(number) over (partition by customer, grp)
    from (select t.*, count(number) over (partition by customer order by date) as grp
          from t
         ) t;
    

    You can also do this with apply, but I suspect the above is faster under almost all circumstances.