2012-03-06 32 views
5

我有一個租用表如下表結構:如何防止SQL中的日期重疊?

hireId int primary key 
carId int not null foreign key 
onHireDate datetime not null 
offHireDate datetime not null 

我試圖編程一個多用戶系統,不允許汽車重疊onhire和停租期間。我需要能夠以非連續順序添加員工。還需要允許編輯僱員。

任何方式來約束表或使用觸發器等,以防止重疊?我使用實體框架,所以我將要插入到表正常,然後如果失敗拋出一些例外開捕等

+3

我能想到的唯一面向數據庫的解決方案是設置一個'INSTEAD OF'觸發器,一個執行檢查的過程。但我會避免它,並檢查代碼中的重疊! – vulkanino 2012-03-06 10:09:30

+0

從實體框架的角度來看,我不認爲我可以在代碼中輕鬆檢查。我可以檢查一點,但有兩個人同時添加/編輯事件的可能性 – GraemeMiller 2012-03-06 10:17:48

+0

我認爲實體框架將使數據訪問更容易,而不是更難!畢竟這是一個簡單的檢查。併發性是一個問題,你可以通過鎖定解決,如果架構允許你(網絡/無狀態?) – vulkanino 2012-03-06 10:27:00

回答

3

考慮這個查詢:如果所有的行都滿足您

SELECT * 
FROM Hire AS H1, Hire AS H2 
WHERE H1.carId = H2.carId 
AND H1.hireId < H2.hireId 
AND 
    CASE 
    WHEN H1.onHireDate > H2.onHireDate THEN H1.onHireDate 
    ELSE H2.onHireDate END 
    < 
    CASE 
    WHEN H1.offHireDate > H2.offHireDate THEN H2.offHireDate 
    ELSE H1.offHireDate END 

業務規則,則該查詢將是空集(假設closed-open representation of periods即結束日期是在期間內未考慮的最早時間粒度)。

因爲SQL Server does not support subqueries within CHECK constraints,把同樣的邏輯觸發(但不是INSTEAD OF觸發,除非你能到決心重疊提供邏輯)。使用Fowler


替代查詢:

SELECT * 
    FROM Hire AS H1, Hire AS H2 
WHERE H1.carId = H2.carId 
     AND H1.hireId < H2.hireId 
     AND H1.onHireDate < H2.offHireDate 
     AND H2.onHireDate < H1.offHireDate; 
+0

所以,如果重疊發生我不應該使用INSTEAD OF觸發器拋出一個異常?我可以捕獲異常並讓用戶修復它。 – GraemeMiller 2012-03-06 13:03:04

+0

@GraemeMiller:使用'AFTER'觸發器。 – onedaywhen 2012-03-06 13:06:41

+0

所以我會插入項目和後觸發器將回滾並提出重疊錯誤? – GraemeMiller 2012-03-06 13:27:41

3
CREATE TRIGGER tri_check_date_overlap ON your_table 
INSTEAD OF INSERT 
AS 
BEGIN 
    IF @@ROWCOUNT = 0 
     RETURN 

    -- check for overlaps in table 'INSERTED' 
    IF EXISTS(
     SELECT hireId FROM your_table WHERE 
      (INSERTED.onHireDate BETWEEN onHireDate AND offHireDate) OR 
      (INSERTED.offHireDate BETWEEN onHireDate AND offHireDate) 
    ) 
     BEGIN 
      -- exception? or do nothing? 
     END 
    ELSE 
     BEGIN 
     END 
END 
GO 
+0

沒有測試它,我不知道檢查實際上是否有效。 – vulkanino 2012-03-06 11:08:40

+0

它不檢查重疊,如果兩個重疊的行插入單個插入語句(既沒有行的表重疊的現有行) – 2012-03-06 11:15:30

+0

@Damien_The_Unbeliever可以更正SP? – vulkanino 2012-03-06 11:17:25

0
我現在用的領域驅動設計技術

。這讓我不必擔心數據庫觸發器等問題,並保留.Net代碼中的所有邏輯。答案在這裏,讓人們可以看到另一種選擇。

我把期間集合的父母當作aggregate root,並且根有一個時間戳。聚合根是事務,分佈和併發性的一致性邊界(請參閱Evans - what I've learned since the blue book)。這用於檢查上次向數據庫確認任何更改的時間。

然後我有方法將聘用期間添加到父項。將運動添加到聚合根時,我會對重疊進行測試。例如AddHire(start,end) - 將驗證這會在內存域對象上創建不重疊。

由於沒有重疊,我保存更改(通過我的存儲庫),並檢查數據庫時間戳是否仍然與流程開始時相同。假設時間戳與我檢索實體時的時間戳相同,則更改將持續存在,並且數據庫會更新時間戳。

如果有人試圖保存更改,當聚合根正在工作時,然後我會先提交或他們會。如果我首先提交時間戳不匹配,重疊檢查將重新運行,以確保它們在間隔時間內未創建重疊。