0

这有点复杂,所以我会尽力解释下面的一切。我已经搜索了一下,我只是无法让它们一起工作。

我有以下表格:

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


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


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

我需要做的是获得一个月的所有事件。但是任何事件都可以有任意数量的日期例外(事件未发生的日期),并且事件可以设置为仅在一周中的某些天运行(例如,仅在周二和周四)。以下是我到目前为止的 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 * 很慢。始终首选只选择您实际需要的列。其次,对于日期范围而言,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

如果您的限定词是“这必须至少在月初开始,并且不能在月结束后的完成日期结束,或者为空,您可以简化:

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

当您使用 OR 子句添加多个谓词(where 语句)时,引擎必须考虑所有这些。你越快确定你的逻辑越好。这可能不是您想要的,但我知道您的逻辑在这里暗示某些逻辑因素将是多余的,例如:

“开始日期总是在连续的结束日期之前吗?” =

应该这样我就不必担心使用结束日期作为起点。这也意味着如果我想在当月得到“完成”的东西,我只需要在小于或等于的范围内寻找结束日期,因为开始日期总是更短,因此不需要合格的。

但是,如果您的订单或产品正在运输中且尚未完成怎么办?根据您的逻辑来填充表,如果您有空值,则可以将其限定出来。但是,有些人在获得所有信息之前不会在表格中输入行,我不知道您的情况。如果你从来没有空值,你可以省略我的括号,只需要:

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