将 WHILE 转换为 CROSS APPLY

Converting WHILE to CROSS APPLY

我有一个标量函数,我正在将其转换为 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 中使用它。

我不太清楚find while循环是怎么转换的,所以纠结其他两个
感谢任何帮助解释第一次转换的帮助。 如果有人可以帮助转换其他两个,那也很有帮助。

您本身不需要 cross apply。显然它只是用来能够从多个地方引用计算表达式。

cross apply中的公式直接计算出你需要添加多少个30天的chunk到@ReviewDueDate,这样就超过了getdate()

  • @ReviewDueDate 和今天之间的天差。
  • 如果 @ReviewDueDate 的时间大于今天的时间,则再加上一天。
  • 将结果天数除以 30.0 以确保它不是 integer division
  • 四舍五入。这是您需要添加的 30 天区块数。
  • 乘以 30 得到天数。

这不能很好地转换为 non-day 间隔,例如月或年。例如,这个:

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.ReviewDueDates 的时间不大于今天的时间,那么 return CA1.ReviewDueDate 未修改天。

所以除了 months/years:

你还需要调整天数的差异
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 中,并在今天已经过去时做一些不同的事情。