Преобразование WHILE в CROSS APPLY - PullRequest
0 голосов
/ 27 июня 2019

У меня есть скалярная функция, которую я конвертирую в TVF.

В скалярной функции у меня есть следующее выражение while:

WHILE @ReviewDueDate < getdate() 
    SET @ReviewDueDate = DATEADD(DAY, 30, @ReviewDueDate)

Когда я помещаю это в TVFЯ использую CROSS APPLY (получил некоторую помощь в конвертации), и он преобразуется в приведенный ниже код:

CROSS APPLY (
    VALUES(DATEADD(DAY, 30 * CEILING(( IIF(CAST(GETDATE() AS TIME) > CAST(CA1.ReviewDueDate AS TIME), 1, 0) + DATEDIFF(DAY, CA1.ReviewDueDate, GETDATE()) ) / 30.0), CA1.ReviewDueDate))
) CA2(ReviewDueDate)

Я не совсем понимаю часть преобразования.
Я понимаю, что когда @ReviewDate < getdate(), К @ReviewDate.
нужно добавить 30 дней. Я немного растерялся, когда пытался понять преобразованный код CROSS APPLY.

Теперь сложная часть для меня:
У меня есть еще два цикла while, как показано ниже:

WHILE @ReviewDueDate < getdate() 
    SET @ReviewDueDate = DATEADD(Month, 6, @ReviewDueDate)
WHILE @ReviewDueDate < getdate() 
    SET @ReviewDueDate = DATEADD(YEAR, 1, @ReviewDueDate)

Так что мне нужно преобразовать его, чтобы использовать его в CROSS APPLY.

Я не понимаю, как найти времяцикл преобразован, поэтому я борюсь с двумя другими.
Любая помощь в объяснении первого преобразования приветствуется.Если кто-то может помочь преобразовать два других, это тоже будет полезно.

1 Ответ

1 голос
/ 27 июня 2019

Вам не нужно cross apply как таковое. По-видимому, он просто использовался, чтобы иметь возможность ссылаться на вычисленное выражение из нескольких мест.

Формула в cross apply напрямую вычисляет, сколько 30-дневных чанков нужно добавить к @ReviewDueDate, чтобы оно превысило getdate():

  • Возьмите разницу в днях в днях между @ReviewDueDate и сегодняшним днем.
  • Если время дня @ReviewDueDate больше времени дня сегодняшнего дня, добавьте к нему один день.
  • Разделите полученное количество дней на 30.0, чтобы убедиться, что это не целочисленное деление .
  • Округли. Это количество 30-дневных чанков, которое нужно добавить.
  • Умножьте его на 30, чтобы получить количество дней.

Это не очень хорошо подходит для недневных интервалов, таких как месяцы или годы. Например, это:

DATEADD(month, 6 * CEILING(( IIF(CAST(getdate() AS TIME) > CAST(CA1.ReviewDueDate AS TIME), 1, 0) + DATEDIFF(month, CA1.ReviewDueDate, getdate()) ) / 6.0), CA1.ReviewDueDate);

будет неправильным, так как он вернет CA1.ReviewDueDate без изменений, если сегодняшняя дата была в том же месяце, а время CA1.ReviewDueDate не было больше, чем сегодняшнее время дня.

Таким образом, вам нужно скорректировать разницу в днях в дополнение к месяцам / годам:

DATEADD(
  month,
  6 * CEILING(  (IIF(  (day(getdate()) > day(CA1.ReviewDueDate) or CAST(getdate() AS TIME) > CAST(CA1.ReviewDueDate AS TIME)), 1, 0) + DATEDIFF(month, CA1.ReviewDueDate, getdate())) / 6.0  ),
  CA1.ReviewDueDate
)
DATEADD(
  year,
  1 * CEILING(  (IIF(  (month(getdate()) > month(CA1.ReviewDueDate) or day(getdate()) > day(CA1.ReviewDueDate) or CAST(getdate() AS TIME) > CAST(CA1.ReviewDueDate AS TIME)), 1, 0) + DATEDIFF(year, CA1.ReviewDueDate, getdate())) / 1.0  ),
  CA1.ReviewDueDate
)

Все это строго предполагает, что CA1.ReviewDueDate всегда меньше, чем getdate(). Если это не так, вы хотите обернуть все это в другой case when ... end, который обрабатывает это дело и делает что-то другое, когда оно уже прошло сегодня.

...