2015-04-01 60 views
0

我有一張表,其中包含一個人的日期和更多數據的列表。該表不應該有任何未刪除的重疊行(日期重疊)。插入/更新時檢查重疊日期

有沒有一種方法可以在表上設置檢查約束,以確保當我更新或插入一行時,沒有重疊的細節?

下面是我的桌子的減少版本。它有一個已刪除的標誌和開始/結束日期。 「空」結束日期表示正在進行。

然後我提供了一些法律和一些不那麼合法的插入(以及爲什麼它們是合法的和非法的)。

DECLARE @Test TABLE 
(
    Id INT NOT NULL IDENTITY(1,1), 
    PersonID INT NOT NULL, 
    StartDate DATE NOT NULL, 
    EndDate DATE NULL, 
    Deleted BIT NOT NULL 
) 


INSERT INTO @Test 
(PersonId, StartDate, EndDate, Deleted) 
SELECT 1, '01-JAN-2015', '15-JAN-2015', 0 UNION ALL -- Valid 
SELECT 1, '16-JAN-2015', '20-JAN-2015', 1 UNION ALL -- Valid and deleted 
SELECT 1, '18-JAN-2015', NULL, 0 UNION ALL -- Valid 
SELECT 2, '01-JAN-2015', NULL, 0 UNION ALL -- Valid.. never ending row. 
SELECT 2, '18-JAN-2015', '30-JAN-2015', 0 UNION ALL -- Invalid! Overlaps above record. 
SELECT 2, '20-JAN-2015', '30-JAN-2015', 1 UNION ALL -- Valid, as it's deleted (Still overlaps, though) 
SELECT 3, '01-JAN-2015', '10-JAN-2015', 0 UNION ALL -- Valid 
SELECT 3, '10-JAN-2015', NULL, 0 -- Invalid, as it overlaps the last and first days 

SELECT * FROM @Test 

我需要確保該表不允許同一個人的重疊日期,對於未刪除的行。

對於日期範圍檢查,我將使用「(StartA < = EndB)和(EndA> = StartB)」公式,但不確定如何使用約束和跨多行檢查此問題。

我可能需要做一個觸發器,通過檢查insertion.values退出,並以某種方式取消,如果我找到匹配?

回答

0

你不能使用CHECK約束沒有添加additional columns。 您必須創建一個Trigger來檢查插入的日期範圍是否不重疊。像這樣的東西..

CREATE TRIGGER [dbo].[DateRangeTrigger] 
    ON [dbo].Test AFTER INSERT, UPDATE 
AS 
BEGIN 
DECLARE @MaxDate DATE = '2999/12/31' 
    IF EXISTS (SELECT t.StartDate, t.EndDate FROM Test t 
      Join inserted i 
      On i.PersonID = t.PersonID 
      AND i.id <> t.Id 
      AND(
       (i.StartDate > t.StartDate AND i.StartDate < ISNULL(t.EndDate,@MaxDate)) 
       OR (ISNULL(i.EndDate,@MaxDate) < ISNULL(t.EndDate,@MaxDate) AND ISNULL(i.EndDate,@MaxDate) > t.StartDate) 
       OR (i.StartDate < t.StartDate AND ISNULL(i.EndDate,@MaxDate) > ISNULL(t.EndDate,@MaxDate)) 
       ) 
      WHERE t.Deleted = 0 AND i.Deleted = 0 
      ) 
    BEGIN 
     RAISERROR ('Inserted date was within invalid range', 16, 1) 
     IF (@@TRANCOUNT>0) 
      ROLLBACK 
    END 

END 

您可以參考這些線程中的一個以獲取更多信息

Enforcing unique date range fields in SQL Server 2008

Unique date range fields in SQL Server 2008

0

這裏有一個基於觸發器的方法:

CREATE TRIGGER [dbo].[trigPersonnel_PreventOverlaps] 
    ON [dbo].[Personnel] 
    AFTER INSERT, UPDATE 
AS 
BEGIN 

    IF EXISTS(
     SELECT * FROM DateRange p 
     INNER JOIN inserted i ON i.PersonID = p.PersonID 
       AND i.Id != p.Id AND i.Deleted = 0 
     AND (
      (p.StartDate <= i.StartDate 
       AND (i.StartDate <= p.EndDate OR p.EndDate IS NULL)) 
      OR (p.StartDate <= i.EndDate 
       AND (i.EndDate <= p.EndDate OR p.EndDate IS NULL)) 
     ) 
     WHERE p.Deleted = 0 
    ) 
    --RAISEERROR if you want 
    ROLLBACK 
END 

注意 - 它會回滾整個事務,所以你需要單獨執行插入操作,以確保不會被拋出。 如果您需要通過批量插入進行梳理並挑選出不合格的東西,則需要更復雜的東西。