小编典典

防止使用SQL触发器插入重叠的日期范围

sql

我有一个简化的表格,如下所示:

create table Test
(
 ValidFrom date not null,
 ValidTo date not null,
 check (ValidTo > ValidFrom)
)

我想编写一个触发器,以防止插入与现有日期范围重叠的值。我写了一个触发器,看起来像这样:

create trigger Trigger_Test
on Test
for insert
as
begin
 if exists(
  select *
  from Test t
   join inserted i
   on ((i.ValidTo >= t.ValidFrom) and (i.ValidFrom <= t.ValidTo))
 )
 begin
  raiserror (N'Overlapping range.', 16, 1);
  rollback transaction;
  return
 end;
end

但这是行不通的,因为我新插入的记录是两个表 Test的 一部分,并且在触发器内 插入
。因此,插入表中的新记录总是在测试表中与其自身联接。触发器将始终还原翻译。

我无法将新记录与现有记录区分开。因此,如果我排除相同的日期范围,则可以在表格中插入多个完全相同的范围。

主要的问题是

是否有可能编写一个可以按预期工作的触发器,而无需在我的Test表中添加其他标识列,而该列可用于从exists()语句中排除新插入的记录,例如:

create trigger Trigger_Test
on Test
for insert
as
begin
 if exists(
  select *
  from Test t
   join inserted i
   on (
    i.ID <> t.ID and /* exclude myself out */
    i.ValidTo >= t.ValidFrom and i.ValidFrom <=t.ValidTo
   )
 )
 begin
  raiserror (N'Overlapping range.', 16, 1);
  rollback transaction;
  return
 end;
end

重要提示 :如果 没有身份不可能 的唯一答案,我欢迎您提出,并提供合理的解释。


阅读 248

收藏
2021-04-22

共1个答案

小编典典

进行两个小更改,一切都应该正常进行。

首先,在触发器中添加一个where子句,以将重复的记录从联接中排除。这样您就不会将插入的记录与其自身进行比较:

select *
  from testdatetrigger t
   join inserted i
   on ((i.ValidTo >= t.ValidFrom) and (i.ValidFrom <= t.ValidTo))
  Where not (i.ValidTo=t.Validto and i.ValidFrom=t.ValidFrom)

除此之外,这将允许精确的重复范围,因此您将必须在两列之间添加唯一约束。实际上,您可能希望每列都具有唯一约束,因为默认情况下,同一天开始(或结束)的任何两个范围都是重叠的。

2021-04-22