我有一张月产值的表格。
例:
Outdate | Prod Value | ID
2/28/19 | 110 | 4180
3/31/19 | 100 | 4180
4/30/19 | 90 | 4180
我还有一个具有月度预测值的表格。
例:
Forecast End Date | Forecast Value | ID
2/28/19 | 120 | 4180
3/31/19 | 105 | 4180
4/30/19 | 80 | 4180
我想创建一个包含ID,Prod Value,当前月份(例如:March)预测,上个月预测,下个月预测的行的表。
我想要的是:
ID | Prod Value | Outdate | Current Forecast | Previous Forecast | Next Forecast
4180 | 100 | 3/31/19 | 105 | 120 | 80
问题是,当我使用DATEADD
从上个月的Forecast表中引入特定值时,我的最终值中缺少随机月份。
在添加下个月和上个月预测时,我尝试使用DateDimension表添加另一个LEFT JOIN
/ INNER JOIN
,但这不能解决问题或添加太多行。
我的DateDimension表包含以下列:DateKey Date,Day,DaySuffix,Weekday,WeekDayName,IsWeekend,IsOoliday,DOWInMonth,DayOfYear,WeekOfMonth,WeekOfYear,ISOWeekOfYear,Month,MonthName,Quarter,QuarterName,Year,MMYYYY,MonthYear,FirstDayOfMonth,LastDayOfMonth ,FirstDayOfQuarter,LastDayOfQuarter,FirstDayOfYear,LastDayOfYear,FirstDayOfNextMonth,FirstDayOfNextYear
我的查询是沿着这些方向(简称为简称)
SELECT A.ArchiveKey, BH.ID, d.[Date], BH.Outdate, BH.ProdValue, BH.Forecast, BHP.Forecast, BHN.Foreceast
FROM dbo.BudgetHistory bh
INNER JOIN dbo.DateDimension d ON bh.outdate = d.lastdayofmonth
INNER JOIN dbo.Archive a ON bh.ArchiveKey = a.ArchiveKey
LEFT JOIN dbo.BudgetHistory bhp ON bh.ID = bhp.ID AND bhp.outdate = DATEADD(m, - 1, bh.Outdate)
LEFT JOIN dbo.BudgetHistory bhn ON bh.ID = bhn.ID AND bhn.outdate = DATEADD(m, 1, bh.Outdate)
WHERE bh.ID IS NOT NULL
我得到这样的东西:
+------+------------+---------+------------------+-------------------+---------------+
| ID | Prod Value | Outdate | Current Forecast | Previous Forecast | Next Forecast |
+------+------------+---------+------------------+-------------------+---------------+
| 4180 | 110 | 2/28/19 | 120 | NULL | NULL |
| 4180 | 100 | 3/31/19 | 105 | 120 | 80 |
| 4180 | 90 | 4/30/19 | 80 | NULL | NULL |
+------+------------+---------+------------------+-------------------+---------------+
这种模式似乎没有任何合理的说法。我想要为每一行填写值。
您可以加入表格,然后使用窗口函数LEAD()
和LAG()
来恢复下一个和之前的预测值:
SELECT
p.ID,
p.ProdValue,
p.Outdate,
f.ForecastValue,
LAG(f.ForecastValue) OVER(PARTITION BY f.ID ORDER BY f.ForecastEndDate) PreviousForecast,
LEAD(f.ForecastValue) OVER(PARTITION BY f.ID ORDER BY f.ForecastEndDate) NextForecast
FROM prod p
INNER JOIN forecast f ON p.ID = f.ID AND p.Outdate = f.ForecastEndDate
这个带有样本数据的demo on DB Fiddle返回:
ID | ProdValue | Outdate | ForecastValue | PreviousForecast | NextForecast ---: | --------: | :------------------ | ------------: | ---------------: | -----------: 4180 | 110 | 28/02/2019 00:00:00 | 120 | null | 105 4180 | 100 | 31/03/2019 00:00:00 | 105 | 120 | 80 4180 | 90 | 30/04/2019 00:00:00 | 80 | 105 | null
如果新计算的值不是有效日期,则DATEADD
仅进行月末调整。所以DATEADD(month,-1,'20190331')
产生2月28日。但DATEADD(month,-1,'20190228')
产生于1月28日,而不是31日。
我可能会选择GMB's answer。如果你想做一些基于DATEADD
的东西,你可以使用:
bhp.outdate = DATEADD(month, DATEDIFF(month,'20010131', bh.Outdate) ,'20001231')
这总是在上个月的最后一天从bh.OutDate
开始计算,但它通过将其计算为固定日期的偏移量,然后将该偏移量应用于不同的固定日期来实现。
您可以反转20010131
和20001231
的位置来计算月份而不是之前的月份。对他们来说没有任何意义,除了他们都有31天和我们希望申请的“一个月的间隔”关系。