2009-09-11 46 views
0

相關的日期我有,我也有類似的數據庫結構相當多的情況:存儲在SQL

表事件(事件ID INT的PrimaryKey,開始DATETIME,完成DATETIME);和 TABLE EventTask(EventTaskID INT的PrimaryKey,事件ID INT ForeignKey的,TaskStart DATETIME,TaskFinish DATETIME)

1至事件和EventTasks之間一對多的關係,等等

當在事件表中的日期改變時,EventTask日期也需要改變 - 提供的日期函數並不難,但日期操作總是有點棘手。

我想知道是否最好用兩個INTS替換TaskStart DATETIME和TaskFinish DATETIME:一個用於Event.Start偏移量(與Event.Start不同)和一個持續時間。

這樣,日期更新變得更加健壯,因爲只有一行需要更新。

(我規定,這僅適用在EventTask日期是完全依賴於事件日期)

回答

2

是的,這聽起來完全合理的給我。主要的缺點是爲了找到EventTasks的實際時間,你必須執行計算。這會減慢返回時間的任何事情,並且特別會損害在過濾器中涉及EventTask時間的查詢 - 例如「找到所有在時間X和Y之間發生的任務。」那些以前可能已經使用過索引,但無法再使用。

+0

重查詢EventTask時間Jon。無論如何,'原創'設計需要重新創建視圖;我想知道你是否可以在這個視圖上應用索引(按照SQLS2008)? – realcals 2009-09-11 06:31:39

+0

@realcals:可能。我不知道它會有多高效。數據庫工程師有時候會非常聰明的人:)無論如何,在你走得太遠之前要測試一些東西,我會說。 – 2009-09-11 07:02:04

1

如果您使用SQL 2008,則可以使用datetimeoffset數據類型。

如果你想直接獲取數據,沒有太多麻煩,你可以使用computed columns,但如果結果是非確定性的,你可能無法創建索引(或使它們存儲結果) 。

你的結構是這樣的:

TABLE [Event] (
    EventID INT PrimaryKey, 
    Start DATETIME, 
    Finish DATETIME) 

TABLE [EventTask](
    EventTaskID INT PrimaryKey, 
    EventID INT ForeignKey, 
    TaskStart DATETIMEOFFSET, 
    TaskFinish DATETIMEOFFSET, 
    EventTaskStart as [getStartDateByEvent](eventId, TaskStart) <PERSISTED>, 
    EventTaskStop as [getStopDateByEvent](eventId, TaskStart) <PERSISTED>, 
    ) 

FUNCTION [getStartDateByEvent](eventId, TaskStart) as DATETIME 
BEGIN 
    SELECT [EVENT].start + TaskStart from [EVENT] WHERE [EVENT].EVENTID = eventID 
END 

FUNCTION [getStartDateByEvent](eventId, TaskStop) as DATETIME 
BEGIN 
    SELECT [EVENT].[finish] + TaskStop from [EVENT] WHERE [EVENT].EVENTID = eventID 
END 
+0

我看不出有什麼幫助 - 它不會讓你指定一個不同表中的字段的偏移量,是嗎? – 2009-09-11 07:01:17

+0

您仍然必須計算該值。 您不能使用直接引用另一個表的計算列,但可以使用用戶定義函數 – 2009-09-11 07:04:41

+0

以下是帶datetime結果的計算列示例: http://stackoverflow.com/questions/246666/persisting-a- calculate-datetime-column-in-sql-server-2005/247092#247092 – 2009-09-11 07:07:56

0

喬恩斯基特:

進行計算。這將減慢任何返回 次的任何事物,並且特別會損害 涉及 中的EventTask時間的查詢。 「找到我所有在時間X和Y之間發生的任務 」。

在我看來,在編寫基本的數據完整性約束時,您已經有了這個要求,例如,事件的任務日期必須在事件本身的日期之內,例如,擴展您的架構到SQL DLL:

CREATE TABLE Event 
(
EventID INTEGER NOT NULL PRIMARY KEY, 
event_Start DATETIME NOT NULL, 
event_Finish DATETIME NOT NULL, 
CHECK (event_Start < event_Finish), 
UNIQUE (event_Start, event_Finish, EventID) 
) 

CREATE TABLE EventTask 
(
EventTaskID INTEGER NOT NULL PRIMARY KEY, 
EventID INTEGER NOT NULL, 
event_Start DATETIME NOT NULL, 
event_Finish DATETIME NOT NULL, 
FOREIGN KEY (event_Start, event_Finish, EventID) 
    REFERENCES Event (event_Start, event_Finish, EventID) 
    ON DELETE CASCADE 
    ON UPDATE CASCADE, 
event_task_START DATETIME NOT NULL, 
event_task_Finish DATETIME NOT NULL, 
CHECK (event_task_Start < event_task_Finish), 
CHECK (event_Start <= event_task_Start), 
CHECK (event_Finish <= event_task_Finish) 
); 

如果一個事件的任務是連續的,那麼你還需要編寫一個約束,以防止重疊的時期,這將涉及的子查詢(大多數SQL產品不支持本作CHECK約束,例如在SQL Server中,您需要使用觸發器)。如果必須使用時間函數(DATEADD等)重新計算偏移量,那麼性能可能會成爲高活動環境中的問題,更不用說增加SQL DLL代碼的複雜性了。

由於這些原因,我會使用開始和結束數據對按照您的規範建議進行建模。