2009-07-06 35 views
2

比方说,我有两个实体:事件和活动查找使用范围值的时间表 - 实体建模

的事件是指发生在(看似)随机时间,如日出,日落,风暴,雾,等

我有这样的表:

create table Event (
eventKey int, 
eventDesc varchar(100), 
started datetime 
) 

EventKey | EventDesc | Started 
1   "Sunset"  2009-07-03 6:51pm 
2   "Sunrise" 2009-07-04 5:33am 
3   "Fog"  2009-07-04 5:52pm 
4   "Sunset"  2009-07-04 6:49pm 
5   "Full Moon" 2009-07-04 10:12pm 
6   "Sunrise" 2009-07-05 5:34am 

然后,我有那人参加了活动表,它们涉及到事件(即动作可能是长时间运行和跨越多个活动:“周末露营”):

create table EventTask (
activityKey int, 
activityDesc varchar(100), 
startEventKey int, 
endEventKey int 
) 

ActivityKey | ActivityDesc | StartEventKey | EndEventKey 
123    "Camp-out"  1    5 
234    "Drive home" 6    6 

我要输出的由所发生的事件标志着行动的时间表:

ActivityKey | ActivityDesc | EventKey | EventDesc 
123    "Camp-out"  1   "Sunset" 
123    "Camp-out"  2   "Sunrise" 
123    "Camp-out"  3   "Fog" 
123    "Camp-out"  4   "Sunset" 
123    "Camp-out"  5   "Full Moon" 
234    "Drive Home" 6   "Sunrise" 

是否可以编写一个查询,将在线性时间,similar to this question做到这一点?另请推荐您可以想到的索引或任何其他优化。目前的解决方案是用C#编写的,但我很喜欢快速的SQL解决方案。

什么是最佳查询来做到这一点?

+0

我有个疑问,EventKey总是按时间排序,还是你的例子是一个特定的情况? – 2009-07-06 06:29:35

+0

是的 - 如果有帮助,您可以假设事件密钥随时间单调递增。 – 2009-07-06 14:46:16

回答

2
/* 
create table Event (
eventKey int, 
eventDesc varchar(100), 
started timestamp 
); 

insert into event values(1,   'Sunset' , '2009-07-03 6:51pm'); 
insert into event values(2,   'Sunrise', '2009-07-04 5:33am'); 
insert into event values(3,   'Fog'  , '2009-07-04 5:52pm'); 
insert into event values(4,   'Sunset' , '2009-07-04 6:49pm'); 
insert into event values(5,   'Full Moon', '2009-07-04 10:12pm'); 
insert into event values(6,   'Sunrise' , '2009-07-05 5:34am'); 

select * from event; 

create table EventTask (
activityKey int, 
activityDesc varchar(100), 
startEventKey int, 
endEventKey int 
) 

insert into eventtask values(123 ,   'Camp-out',  1 ,    5); 
insert into eventtask values(234,    'Drive home', 6,    6); 

select * from eventtask; 

*/ 

select a.activitykey, a.activitydesc, b.eventkey, b.eventdesc 
from 
     eventtask a 
join event b on b.eventkey between a.starteventkey and a.endeventkey 
order by 
     a.activitykey, b.eventkey; 

activitykey  activitydesc  eventkey  eventdesc  
-------------- --------------- ----------- ------------ 
123    Camp-out   1   Sunset  
123    Camp-out   2   Sunrise  
123    Camp-out   3   Fog   
123    Camp-out   4   Sunset  
123    Camp-out   5   Full Moon  
234    Drive home  6   Sunrise  

6 record(s) selected [Fetch MetaData: 3/ms] [Fetch Data: 1/ms] 

[Executed: 7/7/09 4:24:34 PM EDT ] [Execution: 15/ms] 

如果你的表是大的,你肯定会想在event.eventkey,eventtask.starteventkey和eventtask.endeventkey指标。

请注意,索引可提高查询速度,但插入和更新速度较慢。

这里是不需要的event.eventkey列有统计学意义(更正确的)版本:

select a.activitykey, a.activitydesc, d.eventkey, d.eventdesc 
from 
     eventtask a 
join event  b on b.eventkey = a.starteventkey 
join event  c on c.eventkey = a.endeventkey 
join event  d on d.started between b.started and c.started 
order by 
     a.activitykey, d.started; 

activitykey  activitydesc  eventkey  eventdesc  
-------------- --------------- ----------- ------------ 
123    Camp-out   1   Sunset  
123    Camp-out   2   Sunrise  
123    Camp-out   3   Fog   
123    Camp-out   4   Sunset  
123    Camp-out   5   Full Moon  
234    Drive home  6   Sunrise  

6 record(s) selected [Fetch MetaData: 2/ms] [Fetch Data: 0/ms] 

[Executed: 7/8/09 10:01:25 AM EDT ] [Execution: 4/ms] 
+0

非常有趣的解决方案!我不会想象这样做,但我喜欢它。 – 2009-07-09 18:51:23

1

我会重新定义活动表,以便有一个开始时间和结束时间的,而不是在它的基础随机事件。那么如果我真的想看看在那段时间里发生了什么“事件”,我会加入时间范围。从面向对象/灵活性角度来看,这样做更有意义,但您会看到更高的性能成本。

declare @Event table(
id int, 
name varchar(100), 
[time] datetime 
); 

insert into @Event values(1, 'Sunset', '2009-07-03 6:51pm'); 
insert into @Event values(2, 'Sunrise', '2009-07-04 5:33am'); 
insert into @Event values(3, 'Fog', '2009-07-04 5:52pm'); 
insert into @Event values(4, 'Sunset', '2009-07-04 6:49pm'); 
insert into @Event values(5, 'Full Moon', '2009-07-04 10:12pm'); 
insert into @Event values(6, 'Sunrise', '2009-07-05 5:34am'); 

select * from @Event; 

declare @Activity table (
id int, 
name varchar(100), 
startTime datetime, 
endTime datetime 
) 

insert into @Activity values(123, 'Camp-out', '2009-07-03 6:00pm', '2009-07-05 5:00am'); 
insert into @Activity values(234, 'Drive home', '2009-07-05 5:00am', '2009-07-05 6:00am'); 

select * 
from @Activity A 
join @Event E on E.[time] > A.startTime and E.[time] < A.endTime 
order by A.startTime 
1

我最近写了两个方法来优化这些查询(加入上BETWEEN条件):Using CROSS APPLY to optimize joins on BETWEEN conditions

可能的查询(不可能测试没有样品插入):

SELECT et.activityKey, 
et.activityDesc, 
e.* 
FROM Event AS e CROSS APPLY(SELECT TOP 1 * FROM EventTask AS et 
WHERE et.startEventKey <= e.started 
AND e.started < endEventKey 
ORDER BY et.startEventKey 
) AS et