2014-07-02 98 views
1

我想問你一個設計問題:DB設計M:N表的時間間隔

我設計一個表,讓我抓我的頭,不知道最好的方法是什麼,我覺得我缺少一些東西:

它們之間有兩個表A和B以及一個M:N關係表。關係表有現在這些值: A.ID,B.ID,發件人,收件人

經營業務的要求: 在任何時候,A:B關係的船隻能是1:1 A:B可以重複在From和To datetime值中定義的時間,其指定間隔

示例:Car/Driver。 任何車在任何時間只能有一個司機 任何司機可以在任何時間只駕駛1輛車(這不是一定的,好嗎?:)) 司機可以在一段時間後改變車,並可以返回到同一輛車

現在,我不確定: - 我應該跟什麼PK? A,B是不夠的,加入From和To並不合適,也許是一個自動增量PK? - 通過DB設計強制實現業務需求的方法?由於商業原因,我寧願不要在歷史表中。爲什麼?那麼,讓我們假設這輛汽車是租賃的,並且我想知道,給定一個日期,誰在那個日期租了什麼車。拆分爲歷史表將需要更多的joinst :(

我覺得我失去了一些東西,某種一般拍打的......或者我不知道....

感謝任何幫助,所以謝謝你:)

回答

0

我不認爲你真的錯過了什麼。我認爲你已經掌握了問題所在。

我讀過幾篇關於如何在關係數據庫中處理「臨時」數據的文章。

底線的共識是,傳統的關係模型沒有任何支持時間數據的內建機制。

有幾種方法,有些方法比其他方法更適合特殊要求,但所有方法都覺得它們是「管道錄音」。 (我想說的是「狂奔」,但我認爲在紅綠的帽子頂端是:「......雜工的祕密武器,膠帶」和「如果女人不穿着」找不到你帥,他們至少應該在你覺得得心應手。「)


至於作爲主鍵或唯一鍵的表,你可以使用的(a_id, b_id, from)組合。這將給該行一個唯一的標識符。

但是,這並沒有做任何事情來防止重疊的「時間」範圍。

對於防止「重疊」日期時間範圍存儲爲「開始」,「結束」或「開始」,「持續時間」等的MySQL表沒有聲明性約束(至少在一般情況下。如果你有很好的定義範圍,並且觸發器將from四捨五入到四個小時的邊界,並且持續時間恰好爲四個小時,那麼可以使用UNIQUE約束。在更一般的情況下,對於任何ol'值fromto,UNIQUE約束對我們不起作用。

A CHECK約束不足(因爲您需要查看其他行),即使可能,MySQL實際上也不會強制執行檢查約束。

獲得數據庫強制執行此限制的唯一方法是TRIGGER,該方法查找受影響(插入/更新)的行將與其衝突的另一行的存在。

你需要一個BEFORE INSERT觸發器和一個BEFORE UPDATE觸發器。觸發將需要查詢表,以檢查是否存在行的是「重疊」的新/修改的行

SELECT 1 
    FROM mytable t 
WHERE t.a_id = NEW.a_id 
    AND t.b_id = NEW.b_id 
    AND t.from <> OLD.from 
    AND < (t.from, t.to) overlaps (NEW.from,NEW.to) > 

很明顯,最後一行是爲將需要的實際語法僞代碼。

之前的行只會在BEFORE UPDATE觸發器中需要,所以我們不會找到(作爲「匹配」)被更新的行。實際檢查將取決於選擇PRIMARY KEY(或UNIQUE KEY)(s)。

對於MySQL 5.5,如果我們發現新的/更新的行違反了約束,我們可以使用SIGNAL語句返回一個錯誤。對於以前版本的MySQL,我們可以通過執行導致實際錯誤發生的事情來「拋出」錯誤,例如對我們知道不存在的表名稱運行查詢。

最後,這種類型的功能不一定必須在數據庫觸發器中實現;這可以在客戶端處理。

0

如何三個表: TCAR,TDriver,的TLog

TCAR pkCarID fkDriverID 名

駕駛員唯一索引可確保駕駛員僅在一個汽車如初。將外鍵 fkDriverID轉換爲1:1關係。

TDriver pkDriverID 名

的TLog pkLogID(替代PK) fkCarID fkDriverID 從 到

隨着2聯接,你會得到你所描述的任何信息。如果您只需要通過cardid通過driverID或驅動程序數據查找Car數據,則可以通過一次連接完成。

0

謝謝大家對您輸入的,到目前爲止,我一直在思考這個方法,會爲任何批評心存感激/指出破綻: 表(pseudoSQLcode):

Car (ID pk auto_increment, name) 
Driver(ID pk auto_increment, name) 
Assignment (CarID unique,DriverID unique,from Datetime), composite PK (CarID,DriverID) 
AssignmentHistory (CarID unique,DriverID unique,from Datetime,to Datetime) no pk 
當然

,CarID是FK到車(ID)和DriverID是FK到驅動程序(ID)

下一階段是兩個觸發器(和男孩哦,男孩,我希望這可以在MySQL中完成(工作在MSSSQL,但我沒有mysql db現在可以測試):

!!! W arning,MSSQL現在

create trigger Assignment _Update on Assignment instead of update as 
    delete Assignment 
     from Assignment 
      join inserted 
      on ( inserted.CarID= Assignment .CarID 
        or inserted.DriverID= Assignment .DriverID) 
       and (inserted.CarID<> omem.CarID or inserted.DriverID<> omem.DriverID) 
    insert into Assignment 
    select * from inserted; 



create trigger Assignment _Insert on Assignment after delete as 
    insert into Assignment_History 
    select CarID,DriverID,from,NOW() from deleted; 

我測試了一下,似乎每個經營業務情況下,它做什麼,我需要做的