我找去增加一个约束到一个表,实际上是在记录,在该表中记录的其余部分之间的关系的唯一索引的最佳方式。
下表描述各种警卫巡逻想象(从以前的巡夜的情况)
PK PatrolID Integer
FK GuardID Integer
Starts DateTime
Ends DateTime
我们先从约束指定的开始和结束时间必须是合乎逻辑的:
Ends >= Starts
不过,我要添加另一个逻辑约束:一个特定的后卫(GuardID)不能在同一时间两个地方,这意味着任何记录的开始/结束指定的时间内不应该由任何其他巡逻定义的时段重叠同样的后卫。
我能想到的,试图接近这两种方法:
创建一个INSTEAD OF INSERT触发器。 然后,该触发器将使用游标要经过插入表格,检查每个记录。 如果任何记录与现有记录相冲突,错误会得到提升。 这两个问题我有这种方法是:我不喜欢在一个现代版本的SQL Server中使用游标,我不知道如何去implimenting相同的逻辑更新。 也有可能是的互相冲突中插入的记录的复杂性。
第二,看似更好,方法是创建一个调用用户定义的函数,将PatrolID,GuardID,的开始和结束的约束。 然后,该函数会做一个WHERE EXISTS查询检查重叠的GuardID /开始/结束是不是原来的PatrolID记录参数的任何记录。 但是我不知道潜在的副作用是什么这种方法可能有。
是第二种方法比较好? 有谁看到任何缺陷,这样的插入/一次更新多个行时为(在这里我很担心,因为该组中的行可能会出现冲突,也就是说,在“插入”有差别的顺序)。 是否有这样做的更好的方法(如一些花哨INDEX把戏?)
使用后触发器的检查重叠约束没有被违反:
create trigger Patrol_NoOverlap_AIU on Patrol for insert, update as
begin
if exists (select *
from inserted i
inner join Patrol p
on i.GuardId = p.GuardId
and i.PatrolId <> p.PatrolId
where (i.Starts between p.starts and p.Ends)
or (i.Ends between p.Starts and p.Ends))
rollback transaction
end
注:触发器中回滚事务,将终止该批次。 与普通的contraint违规,你将无法捕获错误。
这取决于你如何定义时间范围和重叠您可能需要不同的where子句。 例如,如果你希望能够说卫队#1是在X从6:00至7:00,则Y 7:00至8:00上面不允许。 你反而会想:
create trigger Patrol_NoOverlap_AIU on Patrol for insert, update as
begin
if exists (select *
from inserted i
inner join Patrol p
on i.GuardId = p.GuardId
and i.PatrolId <> p.PatrolId
where (p.Starts <= i.Starts and i.Starts < p.Ends)
or (p.Starts <= i.Ends and i.Ends < p.Ends))
rollback transaction
end
当启动是时间的守护开始和结束是守卫结束后无穷小的时刻。
最简单的方法是使用一个存储过程的插入。 该存储过程可以在单个语句插入:
insert into YourTable
(GuardID, Starts, Ends)
select @GuardID, @Starts, @Ends
where not exists (
select *
from YourTable
where GuardID = @GuardID
and Starts <= @Ends
and Ends >= @Start
)
if @@rowcount <> 1
return -1 -- Failure
根据我的经验,并触发与UDF的限制往往会变得非常复杂。 他们有副作用,可能需要大量的调试搞清楚。
存储过程只是工作,而且他们有一个好处,你可以拒绝INSERT权限给客户,让您在什么进入你的数据库的细粒度控制。
CREATE TRIGGER [dbo].[emaill] ON [dbo].[email]
FOR INSERT
AS
BEGIN
declare @email CHAR(50);
SELECT @email=i.email from inserted i;
IF @email NOT LIKE '%_@%_.__%'
BEGIN
print 'Triggered Fired';
Print 'Invalid Emaill....';
ROLLBACK TRANSACTION
END
END
可以用约束来完成过:
http://www2.sqlblog.com/blogs/alexander_kuznetsov/archive/2009/03/08/storing-intervals-of-time-with-no-overlaps.aspx