DATEADD在与自己连接同一个表时如何工作?

问题描述 投票:1回答:2

我有一张月产值的表格。

例:

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          |
+------+------------+---------+------------------+-------------------+---------------+

这种模式似乎没有任何合理的说法。我想要为每一行填写值。

sql sql-server sql-server-2012 dateadd
2个回答
2
投票

您可以加入表格,然后使用窗口函数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

0
投票

如果新计算的值不是有效日期,则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开始计算,但它通过将其计算为固定日期的偏移量,然后将该偏移量应用于不同的固定日期来实现。

您可以反转2001013120001231的位置来计算月份而不是之前的月份。对他们来说没有任何意义,除了他们都有31天和我们希望申请的“一个月的间隔”关系。

© www.soinside.com 2019 - 2024. All rights reserved.