[英]Prevent inserting overlapping date ranges using a SQL trigger
我有一個簡化的表格如下:
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表中與其自身連接。 觸發器將始終恢復轉換。
我無法區分新記錄和現有記錄。 因此,如果我排除相同的日期范圍,我將能夠在表格中插入多個完全相同的范圍。
是否可以編寫一個可以按預期工作的觸發器,而無需在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
重要提示 :如果不可能沒有身份是唯一的答案,我歡迎您提出一個合理的解釋原因。
我知道這已經回答了,但我最近解決了這個問題,並提出了一些有效的方法(並且對每個插入的行執行單例搜索都表現良好)。 請參閱本文中的示例: 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)
除此之外,這將允許精確的重復范圍,因此您必須在兩列中添加唯一約束。 實際上,您可能希望每列都有唯一約束,因為默認情況下,同一天開始(或完成)的任何兩個范圍都是重疊的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.