我创建了一个函数,该函数使用日历表计算两个日期之间的工作日数量,以排除假日和周末。
CREATE FUNCTION dbo.BusinessDays
(@sDate SMALLDATETIME,
@eDate SMALLDATETIME)
RETURNS TABLE
AS
RETURN (SELECT COUNT(*) dt
FROM dbo.Calendar
WHERE dt BETWEEN @sDate AND @eDate)
Go
我的问题是:如何使用这个函数从另一个有两个日期列的表(dbo.HolidayRequestForm
)中计算列?
我试过了
ALTER TABLE Test
ADD HoursTaken AS dbo.BusinessDays ([StartDate], [FinishDate])
发布于 2018-12-20 17:06:37
我认为最好的做法是重构函数以返回标量值:
CREATE FUNCTION dbo.BusinessDays
(
@sDate SMALLDATETIME,
@eDate SMALLDATETIME
)
RETURNS INT
AS
BEGIN
DECLARE @RTN INT;
SELECT @RTN = COUNT(*)
FROM dbo.Calendar
WHERE dt BETWEEN @sDate AND @eDate;
RETURN @RTN;
END
然后添加计算列的SQL将保持不变。
如果您的函数需要保留为表值函数,则需要使用CROSS APPLY
SELECT *
FROM dbo.HolidayRequestForm
CROSS APPLY dbo.BusinessDays(StartDate, FinishDate) d
正如您所看到的,这会使使用计算列变得相当棘手。
几个不相关的观点:
HoursTaken
是否是计算列的最佳名称,因为它似乎在存储两个日期之间的天数(而不是小时)。WHERE DateColumn >= @DateStart AND DateColumn < @EndDate
。有关更多信息,请参见这篇博客文章。发布于 2018-12-20 19:51:39
想要使用内联(纯) to函数是正确的。Server中有两种类型的Table函数:内联表值函数和错误函数.不幸的是,您不能为计算列使用内联表值函数,而且,如果性能非常重要,不希望对计算列使用T标量UDF。
好消息是你不需要这么做。你有几个选择。首先,不需要日历表来计算工作日,您可以将此逻辑用于计算列:
CASE WHEN SIGN(DATEDIFF(dd, @startDate, @endDate)) > -1 THEN
(DATEDIFF(dd, @startDate, @endDate) + 1) --total days including weekends
-(DATEDIFF(wk, @startDate, @endDate) * 2) --Subtact 2 days for each full weekend
-- Subtract 1 when startDate is Sunday and Substract 1 when endDate is Sunday:
-(CASE WHEN DATENAME(dw, @startDate) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, @endDate) = 'Saturday' THEN 1 ELSE 0 END)
您还可以使用此逻辑创建索引视图,该视图更灵活,也可能是更好的选择。
下面有几个很好的链接,说明为什么您从不使用T标量UDF作为计算列或约束:
具有(标量udf)的计算列可能影响查询性能。 -Kun Cheng (SQLCAT)
另一个隐藏的并行性杀手:检查约束中的标量UDF - Erik (本文也适用于计算列)
计算列中标量函数不是一个好主意的另一个原因。 - Erik Darling
对调用UDF的约束要小心 - Tibor Karaszi
小心.行-行-操作.udf-服装 - Brian
https://stackoverflow.com/questions/53872407
复制相似问题