Rob*_*nik 7 sql t-sql triggers date-range sql-server-2008
我有一个简化的表格如下:
create table Test
(
ValidFrom date not null,
ValidTo date not null,
check (ValidTo > ValidFrom)
)
Run Code Online (Sandbox Code Playgroud)
我想编写一个触发器来阻止插入与现有日期范围重叠的值.我写了一个如下所示的触发器:
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
Run Code Online (Sandbox Code Playgroud)
但它不起作用,因为我新插入的记录是两个表Test的一部分,并在触发器内插入.因此,插入表中的新记录始终在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
Run Code Online (Sandbox Code Playgroud)
重要提示:如果没有身份是不可能的唯一答案,我欢迎您提出一个合理的解释原因.
我知道这已经回答了,但我最近解决了这个问题,并提出了一些有效的方法(并且对每个插入的行执行单例搜索都表现良好).请参阅本文中的示例:http: //michaeljswart.com/2011/06/enforcing-business-rules-vs-avoiding-triggers-which-is-better/
(并且它没有使用标识列)
进行两个小的更改,一切都会正常工作。
首先,向触发器添加一个 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)
Run Code Online (Sandbox Code Playgroud)
除此之外,这将允许精确的重复范围,因此您必须在两列之间添加唯一约束。实际上,您可能希望对每一列有一个唯一的约束,因为在同一天开始(或结束)的任何两个范围默认情况下都是重叠的。
归档时间: |
|
查看次数: |
8513 次 |
最近记录: |