2009-07-06 29 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