我有这个功能,可以将工作日添加到特定日期并返回日期:
ALTER FUNCTION [dbo].[CalcWorkDaysAddDays]
(@StartDate AS DATETIME, @Days AS INT)
RETURNS DATE
AS
BEGIN
DECLARE @Count INT = 0
DECLARE @WorkDay INT = 0
DECLARE @Date DATE = @StartDate
WHILE @WorkDay < @Days
BEGIN
SET @Count = @Count + 1
SET @Date = DATEADD(DAY, @Count, @StartDate)
IF NOT (DATEPART(WEEKDAY, @Date) IN (1, 7)
OR EXISTS (SELECT *
FROM Holidays_Weeknds
WHERE Date = @Date))
BEGIN
SET @WorkDay = @WorkDay + 1
END
END
RETURN @Date
END
此功能在小型数据集中完美运行。但是我的表中有近70k的记录,我需要在我的表中使用此函数超过10列。问题是当我使用这个功能时,运行时间太长。有什么办法可以加快速度,或者修改更新表格中列的UPDATE
语句吗?我的更新语句如下所示:
UPDATE pt
SET [Predicted_Eng_Comp_date] = [dbo].[CalcWorkDaysAddDays](pt.Actual_Eng_Start_date, 20)
FROM [cntrra20-devbrs].PST.[dbo].[tbl_Project_tracker1] pt
答案 0 :(得分:2)
WHILE
循环(实际上是任何循环)都是糟糕的表现者如果你需要一个函数,最好是一个内联表值函数,即使它只返回一个标量值。
对于一个持久的约会表来说,这是一个完美的情况。
您找到一个示例here
Aaron Bertrand提供了一个很好的方法here
使用您的假期表向表中添加IsHoliday
- 标志。
这是一个很小的模拟来显示原则
DECLARE @mockup TABLE(TheDate DATE, DaysName VARCHAR(100),IsWeekday BIT, IsHoliday BIT)
INSERT INTO @mockup VALUES
({d'2016-12-19'},'Mo',1,0)
,({d'2016-12-20'},'Tu',1,0)
,({d'2016-12-21'},'We',1,0)
,({d'2016-12-22'},'Th',1,0)
,({d'2016-12-23'},'Fr',1,0)
,({d'2016-12-24'},'Sa',0,0)
,({d'2016-12-25'},'Su',0,1)
,({d'2016-12-26'},'Mo',1,1)
,({d'2016-12-27'},'Tu',1,0)
,({d'2016-12-28'},'We',1,0)
,({d'2016-12-29'},'Th',1,0)
,({d'2016-12-30'},'Fr',1,0)
,({d'2016-12-31'},'Sa',0,0)
,({d'2017-01-01'},'Su',0,1)
,({d'2017-01-02'},'Mo',1,0)
,({d'2017-01-03'},'Tu',1,0)
,({d'2017-01-04'},'We',1,0);
- 您的变量
DECLARE @d DATE={d'2016-12-20'};
DECLARE @WorkdaysToAdd INT=5;
- 查询选择TOP X
排序ASC
,然后选择TOP 1
排序DESC
SELECT TOP 1 TheDate
FROM
(
SELECT TOP (@WorkdaysToAdd) TheDate
FROM @mockup
WHERE TheDate>@d
AND IsWeekday=1
AND IsHoliday=0
ORDER BY TheDate ASC
) AS t
ORDER BY t.TheDate DESC
你可以从中创建一个函数,或者将它括义直接包含在你的UPDATE
查询中(而不是你的函数)。
答案 1 :(得分:0)
具有功能的列非常慢。尽量避免:
declare @MinStartDate as date = '1/1/2010'
declare @MaxEndDate as date = '1/1/2020'
declare @numberofdays int = 20
;WITH res(val)
AS
(
select val from (select @MinStartDate as val) as resy
union all
select dateadd(d,1, res.val) from res where res.val < @MaxEndDate
)
UPDATE pt
set [Predicted_Eng_Comp_date]= a.NUMDAYS
from [cntrra20-devbrs].PST.[dbo].[tbl_Project_tracker1] pt
inner join (
SELECT r.val, count(*) as NUMDAYS
FROM [cntrra20-devbrs].PST.[dbo].[tbl_Project_tracker1] pt
inner join res r on pt.Actual_Eng_Start_date = r.val
left join Holidays_Weeknds h on r.val = h.[Date]
where DATEPART(WEEKDAY, r.val) NOT IN (1,7) and h.[Date] is null
and val>=pt.Actual_Eng_Start_date and val<=dateadd(d,@numberofdays, pt.Actual_Eng_Start_date)
group by r.val) a on pt.Actual_Eng_Start_date = a.val
option (MAXRECURSION 32767)
根据计算,您可能希望更改&#39; val&lt; = dateadd&#39; val小于。