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 |