Как работает DATEADD при соединении одной таблицы с самим собой? - PullRequest
1 голос
/ 05 апреля 2019

У меня есть таблица с месячными значениями производства.

Пример:

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

Я хочу создать таблицу, в которой есть строка, содержащая идентификатор, значение Prod Value, прогноз на текущий месяц (пример: март), прогноз на предыдущий месяц, прогноз на следующий месяц.

Что я хочу:

ID | Prod Value | Outdate | Current Forecast | Previous Forecast | Next Forecast
4180 | 100      | 3/31/19 |              105 |               120 | 80

Проблема в том, что когда я использовал DATEADD, чтобы ввести конкретное значение из таблицы «Прогноз» за предыдущий месяц, случайные месяцы отсутствуют в моих окончательных значениях.

Я пытался добавить еще одну LEFT JOIN / INNER JOIN с таблицей DateDimension при добавлении в прогноз на следующий месяц и предыдущий месяц, но это либо не решает проблему, либо добавляет слишком много строк.

Моя таблица DateDimension, в которой есть следующие столбцы: DateKey Дата, День, DaySuffix, День недели, WeekDayName, IsWeekend, IsHoliday, DOWInMonth, DayOfYear, WeekOfMonth, WeekOfYear, ISOWeekOfYear, Месяц, MonthName, Квартал, QuarterName, Год, MMYYYY, Месяц, ГодDayFayOayOayDearOayOayOayDearOayOayDearOayOjOF 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          |
+------+------------+---------+------------------+-------------------+---------------+

И модель, похоже, не следует разумным. Я хочу, чтобы значения были заполнены для каждой строки.

Ответы [ 2 ]

2 голосов
/ 05 апреля 2019

Вы можете присоединиться к таблицам, а затем использовать оконные функции 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

Это демонстрация на DB Fiddle с вашим примером возвращает данные:

  ID | ProdValue | Outdate             | ForecastValue | PreviousForecast | NextForecast
---: | --------: | :------------------ | ------------: | ---------------: | -----------:
4180 |       110 | 28/02/2019 00:00:00 |           120 |             <em>null</em> |          105
4180 |       100 | 31/03/2019 00:00:00 |           105 |              120 |           80
4180 |        90 | 30/04/2019 00:00:00 |            80 |              105 |         <em>null</em>
0 голосов
/ 05 апреля 2019

DATEADD выполняет корректировки на конец месяца только в том случае, если новое вычисленное значение не является действительной датой.Так что DATEADD(month,-1,'20190331') производит 28 февраля.Но DATEADD(month,-1,'20190228') производит 28 января, не 31-го.

Я бы, наверное, согласился с ответом GMB .Если вы хотите сделать что-то на DATEADD основе, вы можете использовать:

bhp.outdate = DATEADD(month, DATEDIFF(month,'20010131', bh.Outdate) ,'20001231')

Это всегда работает в последний день предыдущего месяца с bh.OutDate, но делает это, вычисляя это как смещение от фиксированной даты, а затем применение этого смещения к другой фиксированной дате.

Можно просто поменять местами 20010131 и 20001231, чтобы вычислить месяц после, а немесяцем ранееДля них нет никакого значения, кроме того, что у них обоих есть 31 день и отношения "один месяц", которые мы хотим применить.

...