I am struggling with the following issue (simplified form). I have a table with 53 rows and for column [No of Days] only some of the rows contain a quantity. In the column [Days Calculated] I want to dynamically calculate the Days for the rows that do not contain a quantity, adding the difference between 2 rows with a quantity evenly among the rows without quantity. If there is no difference than use the same quantity.
Rows without a quantity before the first row with a quantity should be filled with quantity of this row. Rows without a quantity after the last row with a quantity should be filled with the quantity of this row.
The source I have are the first 2 columns, I need to add the 3rd column.
| Period No | No of Days | Days Calculated |
|---|---|---|
| 1 | NULL | 77 |
| 2 | NULL | 77 |
| 3 | NULL | 77 |
| removed some rows | NULL | 77 |
| 22 | 77 | 77 |
| 23 | NULL | 75,83 |
| 24 | NULL | 74,66 |
| 25 | NULL | 73,49 |
| 26 | NULL | 72,32 |
| 27 | NULL | 71,15 |
| 28 | 70 | 70 |
| 29 | NULL | 70 |
| removed some rows | NULL | 70 |
| 45 | 70 | 70 |
| 46 | NULL | 73,50 |
| 47 | 77 | 77 |
| 48 | NULL | 77 |
| removed some rows | NULL | 77 |
| 53 | 77 | 77 |
I have tried to solve this with making a ranking and a case statement with the possible conditions but have not been able to completely get it right. I have the feeling there are better ways.
Any guidance in the right direction is much appreciated !
CodePudding user response:
CREATE TABLE testTable (PeriodNo INT, NoOfDaysPL MONEY);
INSERT INTO dbo.testTable(PeriodNo)
SELECT TOP(53)ROW_NUMBER() OVER (ORDER BY t1.object_id) AS N
FROM sys.all_columns t1
CROSS JOIN sys.all_columns AS t2;
UPDATE dbo.testTable SET NoOfDaysPL=77 WHERE PeriodNo=22;
UPDATE dbo.testTable SET NoOfDaysPL=70 WHERE PeriodNo=28;
UPDATE dbo.testTable SET NoOfDaysPL=70 WHERE PeriodNo=45;
UPDATE dbo.testTable SET NoOfDaysPL=77 WHERE PeriodNo=51;
SELECT PeriodNo, NoOfDaysPL,
CASE WHEN pv IS NULL THEN COALESCE(NoOfDaysPL, ndv)
WHEN nv IS NULL THEN COALESCE(NoOfDaysPL, pdv)
WHEN NoOfDaysPL IS NULL THEN pdv-((pdv-ndv)/(nv-pv)*(PeriodNo-pv))
ELSE NoOfDaysPL
END NoOfDaysCalculated
FROM dbo.testTable AS tt
CROSS APPLY(SELECT MAX(PeriodNo)
FROM dbo.testTable AS tt2
WHERE tt2.PeriodNo<tt.PeriodNo AND tt2.NoOfDaysPL IS NOT NULL) p(pv)
CROSS APPLY(SELECT MIN(PeriodNo)
FROM dbo.testTable AS tt2
WHERE tt2.PeriodNo>tt.PeriodNo AND tt2.NoOfDaysPL IS NOT NULL) n(nv)
OUTER APPLY(SELECT NoOfDaysPL FROM dbo.testTable AS tt2 WHERE tt2.PeriodNo=p.pv) pc(pdv)
OUTER APPLY(SELECT NoOfDaysPL FROM dbo.testTable AS tt2 WHERE tt2.PeriodNo=n.nv) nc(ndv);
| PeriodNo | NoOfDaysPL | NoOfDaysCalculated |
|---|---|---|
| 1 | null | 77.0000 |
| 2 | null | 77.0000 |
| 3 | null | 77.0000 |
| 4 | null | 77.0000 |
| 5 | null | 77.0000 |
| 6 | null | 77.0000 |
| 7 | null | 77.0000 |
| 8 | null | 77.0000 |
| 9 | null | 77.0000 |
| 10 | null | 77.0000 |
| 11 | null | 77.0000 |
| 12 | null | 77.0000 |
| 13 | null | 77.0000 |
| 14 | null | 77.0000 |
| 15 | null | 77.0000 |
| 16 | null | 77.0000 |
| 17 | null | 77.0000 |
| 18 | null | 77.0000 |
| 19 | null | 77.0000 |
| 20 | null | 77.0000 |
| 21 | null | 77.0000 |
| 22 | 77.0000 | 77.0000 |
| 23 | null | 75.8334 |
| 24 | null | 74.6668 |
| 25 | null | 73.5002 |
| 26 | null | 72.3336 |
| 27 | null | 71.1670 |
| 28 | 70.0000 | 70.0000 |
| 29 | null | 70.0000 |
| 30 | null | 70.0000 |
| 31 | null | 70.0000 |
| 32 | null | 70.0000 |
| 33 | null | 70.0000 |
| 34 | null | 70.0000 |
| 35 | null | 70.0000 |
| 36 | null | 70.0000 |
| 37 | null | 70.0000 |
| 38 | null | 70.0000 |
| 39 | null | 70.0000 |
| 40 | null | 70.0000 |
| 41 | null | 70.0000 |
| 42 | null | 70.0000 |
| 43 | null | 70.0000 |
| 44 | null | 70.0000 |
| 45 | 70.0000 | 70.0000 |
| 46 | null | 71.1666 |
| 47 | null | 72.3332 |
| 48 | null | 73.4998 |
| 49 | null | 74.6664 |
| 50 | null | 75.8330 |
| 51 | 77.0000 | 77.0000 |
| 52 | null | 77.0000 |
| 53 | null | 77.0000 |
