我有一张表格,其中包含一个人的日期和更多数据列表。该表不应该有任何未删除的重叠行(日期重叠)。
我是否可以在表格上设置检查约束,以确保在更新或插入行时,没有重叠的详细信息?
以下是我桌子的缩减版。它有一个已删除的标志,以及开始/结束日期。 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来实现,如果找到匹配则以某种方式取消?
答案 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
您可以参考其中一个主题获取更多信息
答案 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
注意 - 它会回滚整个交易,因此您需要单独执行插入操作,以确保不会抛出好的插件。 如果你需要一些东西来梳理整体插件并挑出不好的插件,那么你需要更复杂的东西。