0

これは少し複雑なので、以下のすべてを説明するために最善を尽くします。私はこれを少し探しましたが、すべてを一緒に機能させるのに問題があります。

私は次のテーブルを持っています:

Events
----------------
ID int
Name varchar(100)
StartDate datetime
EndDate datetime


EventDaysOfWeek
------------------
EventID int
DayOfWeekNumber int


EventDateExceptions
--------------------
EventID int
ExceptionDate datetime

私がする必要があるのは、1か月間のすべてのイベントを取得することです。ただし、どのイベントにも任意の数の日付例外(イベントが発生しない日付)があり、イベントは特定の曜日(火曜日と木曜日のみなど)にのみ実行されるように設定できます。以下は、渡された開始日と終了日の間にイベントを取得するprocコード(明らかに終了していない)についてこれまでに持っているものです。この場合は、月の始まりと月末になります。

Declare @first datetime,    
@last datetime  

Set @first = '3/1/2013' --first date in the range being checked
Set @last = '3/31/2013' --last date in the range being checked

select * from events     
where   
(startdate BETWEEN @first AND @last   -- starts in month
or enddate BETWEEN @first AND @last) -- ends in month
or ((startDate <= @first and endDate >= @last )) -- spans the entire date range

編集:

これが私の質問に関するいくつかの追加の詳細です:

  • イベントは開始日から終了日まで継続的に実行されます

  • 日付例外が追加された場合、イベントはその日付には発生しません

  • 曜日テーブルは、イベントが発生する曜日を決定します(たとえば、イベントが3月1日= 3月31日に実行される場合、曜日を木曜日に設定できます。これは、イベントが木曜日にのみ実行されることを意味します。開始日と終了日)

もともと私は自分の質問を間違って言いました。私は必要なコードを最適化するつもりはありません(あなたの提案はありがたいですが)開始日と終了日の間に発生するすべてのイベントを返すようにクエリを取得するためのヘルプを探していますが、日付の例外も考慮に入れていますイベントに設定された曜日。

4

2 に答える 2

1

あなたが言ったように、質問は少しあいまいであり、あなたのprocがあなたの「例外」にまったく対処していないように見えるので、後でそれらを追加する予定ですか?

あなたのprocとそのパフォーマンスに関する限り(これは私が見る唯一の本当の質問です)

まず、SELECT*は遅いです。実際に必要な列のみを選択することを常にお勧めします。第2に、Between演算子は通常、<=> =操作を実行するよりも日付範囲の方が高速ですが、常に使用できるとは限りません。

それで:

SELECT [just the columns you need]
FROM events     
WHERE (startDate BETWEEN @start AND @end) -- starts in month
or (endDate BETWEEN @start AND @end) -- ends in month
or (startDate <= @start and endDate >= @end) -- spans the month?

編集これはあなたが求めていることを行うべき完全なSQLクエリです:

declare @startdate date = '2013-03-01'
,@enddate date = '2013-04-01'
,@counter int = 0;
declare @DateTable table (SeqDate Date);

declare @Events table (ID int, Name varchar(100), StartDate Date, EndDate Date);
insert into @Events values(1, '1Event', '2013-03-14', '2013-03-16');
insert into @Events values(2, '2Event', '2013-03-01', '2013-03-13');

declare @EventDateException table (EventId int, ExceptionDate Date);
--insert into @EventDateException values (1, '2013-03-14');
insert into @EventDateException values (1, '2013-03-15');
--insert into @EventDateException values (1, '2013-03-16');

declare @EventDaysOfWeek table (EventId int, DayOfWeekNumber int);
insert into @EventDaysOfWeek values (2, 5);
insert into @EventDaysOfWeek values (2, 6);

/* create a table of all days in the series */
while @startdate < @enddate
begin
insert into @DateTable (SeqDate)
select @startdate
set @startdate = dateadd(dd, 1, @startdate)
set @counter = @counter + 1
end;

select distinct ID, Name from 
--select * from 
@Events e
join @DateTable d
on 1 = 1
left join @EventDateException ex
on e.ID = ex.EventId AND ex.ExceptionDate = d.SeqDate
left join @EventDaysOfWeek dow
on e.ID = dow.EventId
where d.SeqDate BETWEEN e.StartDate AND e.EndDate
AND (d.SeqDate <> ex.ExceptionDate OR ex.ExceptionDate IS NULL)
AND (DATEPART(DW,d.SeqDate) = dow.DayOfWeekNumber OR dow.DayOfWeekNumber IS NULL)
于 2013-03-26T15:46:47.260 に答える
0

修飾子が「少なくとも月の初めに開始点で開始する必要があり、月が終わった後の完了日に終了することはできません。またはnullの場合は、ロジックをやり過ぎていると思います。単純化できます。

Where StartDate >= @Start and (EndDate <= @EndDate or EndDate is not null)

OR句を使用して複数の述語(whereステートメント)を追加する場合、エンジンはそれらすべてを検討する必要があります。ロジックをより早く特定できるほど、より良い結果が得られます。これはあなたが望むものではないかもしれませんが、私はあなたがロジックであなたがここで冗長になる特定のロジックファクターを暗示していることを知っています:

「開始日は常に行の終了日より前になりますか?」=

終了日を開始点として使用することを心配する必要がないようにする必要があります。また、その月に「終了」したものを取得したい場合は、開始日が常に小さいため、終了日は常に以下である必要がないため、終了日を探す必要があることを意味します。資格があります。

ただし、注文または製品が輸送中であり、完成していない場合はどうなりますか?ロジックに応じて、nullがある場合にテーブルを修飾できる値をテーブルに入力します。ただし、すべてを取得するまでテーブルに行を入力しない人もいます。私はあなたの状況を認識していません。nullがない場合は、かっこを省略して、次のようにすることができます。

Where StartDate >= @Start and EndDate <= @EndDate
于 2013-03-26T15:49:13.280 に答える