SQL Server 将 此 标量 UDF 重写 为 内联 TVF

xiozqbni  于 2022-11-21  发布在  其他
关注(0)|答案(2)|浏览(168)

我正在尝试编写以下标量UDF:

CREATE FUNCTION [dbo].[DAYSADDNOWK](@addDate AS DATE, @numDays AS INT)
RETURNS DATETIME
AS
BEGIN
    WHILE @numDays>0
    BEGIN
       SET @addDate=DATEADD(d,1,@addDate)
       IF DATENAME(DW,@addDate)='saturday' SET @addDate=DATEADD(d,1,@addDate)
       IF DATENAME(DW,@addDate)='sunday' SET @addDate=DATEADD(d,1,@addDate)
  
       SET @numDays=@numDays-1
    END
  
    RETURN CAST(@addDate AS DATETIME)
END
GO

作为内联TVF。
我一直在尝试使用TVF中的CTE来替换while循环,但我一直遇到无数的问题,所以如果有人有任何想法并可以帮助我,我将非常感激。
要求:以日期d和整数i作为参数,并返回从传入的日期di个工作日(工作日)的日期。
虽然我很欣赏可能有更好的方法来实现这一点,如果这里有建议,我很乐意阅读它们,但我也很想知道如何在内联TVF中使用递归CTE来实现这一点,因为我更多的是作为实践来做这件事,这样我就可以将此技术应用于更复杂的标量UDF,我可能需要在未来进行重构。

jyztefdp

jyztefdp1#

转换为TVF并消除循环是绝对正确的做法。
正如我所评论的,考虑一个日历表...有很多事情可以很容易地完成。
下面是一个TVF,它使用一个特别的计数表来

CREATE FUNCTION [dbo].[YourFunctionName] (@D date,@I int)
Returns Table
Return (

Select WorkDate = D
      ,WorkDays = RN
 From  (
        Select D
              ,RN = -1+row_number() over( order by D)
         From  (
                Select Top ((@I+1)*2) D=dateadd(DAY,-1+Row_Number() Over (Order By (Select NULL)),@D)
                  From master..spt_values n1, master..spt_values n2
               ) A
         Where datename(WEEKDAY,D) not in ('Saturday','Sunday')
       ) A
 Where RN=@I

)
mqkwyuun

mqkwyuun2#

实际上,我在工作中的一个应用程序中也有类似的需求。
您的标量函数在大约几十天内是非常有用的,但是超过这个时间就会明显地失去性能。
我不能把下面的代码归功于我(因为我知道它是从各种博客/论坛上收集的)--但是去掉一些定制的业务逻辑并适合现有的函数,下面的函数计算日期偏移量,(可能)是您将获得的最佳性能:

create or alter function dbo.DAYSADDNOWK2(@addDate date, @numDays int)
returns datetime
as
begin
  return DateAdd(day,
    case
      when ((DatePart(weekday, @addDate) + 1) % 7 + (@numDays % 5)) > 6 
    then 2 else 0 end + (@numDays % 5), 
    DateAdd(week, (@numDays / 5), @addDate)
  )
end;

相关问题