我有一个触发器:
CREATE TRIGGER tgr_incheck_vlucht
ON PassagierVoorVlucht
AFTER INSERT, UPDATE
AS
BEGIN
IF @@ROWCOUNT= 0 BEGIN RETURN END
SET NOCOUNT ON
BEGIN TRY
IF EXISTS
(SELECT *
FROM inserted I
WHERE EXISTS(SELECT *
FROM PassagierVoorVlucht P inner join Vlucht V on P.vluchtnummer = V.vluchtnummer
WHERE I.inchecktijdstip >= vertrektijdstip))
BEGIN
RAISERROR('Inchecktijdstip moet voor de aankomsttijdliggen', 16,1)
END
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0 BEGIN ROLLBACK TRANSACTION END
DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE(),
@errorSeverity INT = ERROR_SEVERITY(),
@errorState INT = ERROR_STATE()
RAISERROR (@ErrorMessage, @errorSeverity, @errorState)
END CATCH
END
现在我写了一些测试声明:
INSERT INTO PassagierVoorVlucht
VALUES(850, 5316, 1, '2002-01-01 13:37:00.000', 21),
(1002, 5316, 1, '2004-01-01 13:37:00.000', 21),
(1601, 5316, 1, '2004-05-01 13:37:00.000', 21),
(1602, 5316, 1, '2004-05-01 13:37:00.000', 21)
触发器当时仅适用于一个插入行,而不适用于整个块。如何编写可以处理多个插入的触发器?
答案 0 :(得分:1)
答案是你不能......从根本上说,每个插入触发了触发器,而不是一批代码。这就是它被称为触发器或响应的原因。
此外,如果您的表具有Insert Identity列,则触发器不会阻止行中的间隙,因为它们的功能就像序列一样:在行级激活并在语句完成后激活(除非INSTEAD OF)。
在MSDN中解释触发器可能有用:
{{3}}
尽管TRUNCATE TABLE语句实际上是DELETE语句,但它不会激活触发器,因为该操作不会记录单个行删除。但是,只有那些有权执行TRUNCATE TABLE语句的用户才需要担心这种方式无意中绕过DELETE触发器。
请注意有关各行删除的部分以及有关范围的要点。或许更了解您的要求可能会使解决方案更加清晰。
现在,您可以在尝试执行代码之前使用INSTEAD OF
触发器触发,但这可能不会成为解决方案,除非您有一些临时表设置或类似的功能。而不是替换整个DML或DDL语句。
如果您希望保护数据的完整性,请考虑使用存储或预先规划的程序。
如果这是不可接受或不切实际的,可以选择其他约束,如参考密钥甚至临时表(取决于对数据的及时性的需要),以后可以导入。
答案 1 :(得分:1)
为此,您需要在触发器内使用一个临时表并将所有插入的数据存储在其中,然后使用while循环对该表进行循环。 这是一个示例,我们希望使用插入触发器
将所有插入的用户添加到审核表中alter trigger tr_userData_forInsert
on userData
for insert
AS
BEGIN
declare @id int, @name varchar(20)
select *
into #inserted_data
from inserted
while ( exists(select id from #inserted_data) )
begin
select top 1 @id = id, @name = full_name
from #inserted_data
insert into loggs
values ( concat( 'a user with ',@id, ' and name of ', @name
, ' is added at ', getdate() ) )
delete from #inserted_data
where id = @id
end
end
我已经在多种情况下使用了它,并且效果很好