我不認爲你真的錯過了什麼。我認爲你已經掌握了問題所在。
我讀過幾篇關於如何在關係數據庫中處理「臨時」數據的文章。
底線的共識是,傳統的關係模型沒有任何支持時間數據的內建機制。
有幾種方法,有些方法比其他方法更適合特殊要求,但所有方法都覺得它們是「管道錄音」。 (我想說的是「狂奔」,但我認爲在紅綠的帽子頂端是:「......雜工的祕密武器,膠帶」和「如果女人不穿着」找不到你帥,他們至少應該在你覺得得心應手。「)
至於作爲主鍵或唯一鍵的表,你可以使用的(a_id, b_id, from)
組合。這將給該行一個唯一的標識符。
但是,這並沒有做任何事情來防止重疊的「時間」範圍。
對於防止「重疊」日期時間範圍存儲爲「開始」,「結束」或「開始」,「持續時間」等的MySQL表沒有聲明性約束(至少在一般情況下。如果你有很好的定義範圍,並且觸發器將from
四捨五入到四個小時的邊界,並且持續時間恰好爲四個小時,那麼可以使用UNIQUE約束。在更一般的情況下,對於任何ol'值from
和to
,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,我們可以通過執行導致實際錯誤發生的事情來「拋出」錯誤,例如對我們知道不存在的表名稱運行查詢。
最後,這種類型的功能不一定必須在數據庫觸發器中實現;這可以在客戶端處理。