检查插入/更新上的重叠日期

时间:2015-04-01 04:23:34

标签: sql-server sql-server-2008

我有一张表格,其中包含一个人的日期和更多数据列表。该表不应该有任何未删除的重叠行(日期重叠)。

我是否可以在表格上设置检查约束,以确保在更新或插入行时,没有重叠的详细信息?

以下是我桌子的缩减版。它有一个已删除的标志,以及开始/结束日期。 A' Null'结束日期意味着它正在进行中。

然后,我提供了一些合法的,一些不合法的插页(以及为什么他们合法和非法)。

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)"公式,但不确定如何使用约束检查这个,并且跨多行。

我可能需要使用Trigger,通过检查exit的inserted.values来实现,如果找到匹配则以某种方式取消?

2 个答案:

答案 0 :(得分:0)

如果不添加additional columns,则无法使用CHECK约束。 您必须创建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

答案 1 :(得分: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

注意 - 它会回滚整个交易,因此您需要单独执行插入操作,以确保不会抛出好的插件。 如果你需要一些东西来梳理整体插件并挑出不好的插件,那么你需要更复杂的东西。