1

我有一个日期表调用 [BadDates],它只有一列,其中每条记录都是要排除的日期。我有一个UDF如下:

CREATE FUNCTION [dbo].[udf_GetDateInBusinessDays]
(
  @StartDate datetime,  --Start Date
  @NumberDays int           --Good days ahead
)
RETURNS datetime
AS
BEGIN
-- Declare the return variable here
DECLARE @ReturnDate datetime
SET @ReturnDate = @StartDate
DECLARE @Counter int
SET @Counter = 0
WHILE   @Counter < @NumberDays
BEGIN
    SET @ReturnDate = DateAdd(d,1,@ReturnDate)
    IF ((SELECT COUNT(ID)
        FROM dbo.[BadDates]
        WHERE StartDate = @ReturnDate) = 0)
    BEGIN
        SET @Counter = @Counter + 1
    END
END
RETURN @ReturnDate
END

此 UDF 效果很好,但处理速度很慢。使用它的存储过程在每条记录中运行 UDF。是否有其他方法可以以更快的方法提供相同的功能。

任何帮助是极大的赞赏!

4

5 回答 5

2

我假设您要做的是计算给定日期后 x 个工作日的日期。例如,从今天起 10 个工作日后的日期。我还假设您的 baddates 表包含非工作日,例如周末和银行假期。

过去我遇到过类似的要求,通常最终得到包含所有可能日期的天表以及一个指示特定日期是否为工作日的标志。

然后,我使用该表通过选择开始日期后 x 天的记录来计算从提供的日期开始的 x 个工作日的日期。

所以像这样

 CREATE TABLE all_days (  
  dated DATETIME,  
  day_state CHAR(1)  
  )

其中 day_state 是
D - 工作日
W - 周末
B - 银行假日的值

然后在 x 个工作日后查找日期的 SQL 变为

SELECT MAX(dated)
FROM (
  SELECT TOP(@number_days) dated
  FROM all_days
  WHERE day_state = 'D'
  AND dated >= @start_date
  ORDER by dated ASC
)

这段代码未经测试,但应该给你一个大致的想法。您可能不想区分周末和公共假期,在这种情况下,您可以将 day_state 重命名为 working_day 并使其成为 BIT 字段。

您应该在 dated 和 day_state 上创建一个复合唯一索引。

于 2009-05-15T22:07:01.290 回答
2

我没有对此进行测试,但理论上它应该可以工作。我把天数加起来。然后我检查该范围内是否有任何错误。如果有,我会添加糟糕的天数,并检查我刚刚添加的范围内是否还有糟糕的日期。重复直到没有糟糕的日期。

CREATE FUNCTION [dbo].[udf_GetDateInBusinessDays]
(
  @StartDate datetime,  --Start Date
  @NumberDays int           --Good days ahead
)
RETURNS datetime
AS
BEGIN
-- Declare the return variable here
DECLARE @ReturnDate datetime
SET @ReturnDate = dateadd(d, @NumberDays, @StartDate);


DECLARE @d int;
SET @d = (select count(1) from baddates where startdate >= @StartDate and startdate <= @ReturnDate);

declare @t datetime;

WHILE   @d > 0
BEGIN
    set @t = @ReturnDate;
    set @ReturnDate = dateadd(d, @d, @ReturnDate);
    SET @d = (select count(1) from baddates where startdate > @t and startdate <= @ReturnDate);
END

RETURN @ReturnDate
END
于 2009-05-15T22:28:08.153 回答
0

您可能希望在 BadDates.StartDate 上放置一个索引,但可能还有其他更好的解决方案。

于 2009-05-15T21:36:35.373 回答
0

好的,您为什么要计算何时可以使用 EXISTS 关键字?如果是因为您可以在 Badates 中有多个相同类型的日期,这似乎是错误的。当您只需要排除 1 时,COUNT 可能会查看整个表以计算 startdate 的实例。

您是否查看过查询计划以了解发生了什么?

于 2009-05-15T21:48:23.740 回答
0

看起来您正在使用此 UDF 来计算两个日期之间的差异。如果我正确解释了这一点,那么我建议您使用内置的 datediff 函数。

于 2009-05-15T21:49:04.220 回答