1

[BadDates] という日付のテーブルがあります。すべてのレコードが除外する日付である列が 1 つだけあります。次のような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で同じタイプの日付を複数持つことができるため、これは間違っているようです。COUNT はおそらくテーブル全体を調べて、除外する必要があるのが 1 だけの場合に startdate のインスタンスをカウントします。

クエリ プランを見て、何が起こっているかを確認しましたか?

于 2009-05-15T21:48:23.740 に答える
0

この UDF を使用して 2 つの日付の差を計算しているようです。これを正しく解釈している場合は、組み込みの datediff 関数を使用することをお勧めします。

于 2009-05-15T21:49:04.220 に答える