在 MS SQL Server 2008 R2 中,我们需要一个预插入和预更新触发器来检查某些内容并允许或回滚(通过raiserror
)正在运行的插入/更新。
问题:在INSTEAD OF
触发器中。真的必须明确编写插入或更新吗?因为我们希望完成默认的插入或更新,并且只进行“预检查”。
在 MS SQL Server 2008 R2 中,我们需要一个预插入和预更新触发器来检查某些内容并允许或回滚(通过raiserror
)正在运行的插入/更新。
问题:在INSTEAD OF
触发器中。真的必须明确编写插入或更新吗?因为我们希望完成默认的插入或更新,并且只进行“预检查”。
是的。
您确实需要编写显式INSERT
or UPDATE
。
触发器运行INSTEAD OF
DML 操作。如果您将触发器留空,则除了创建和填充的INSERTED
/表之外不会发生任何操作。DELETED
tempdb
尽管从评论中的讨论来看,我根本不会为此使用触发器,而是使用唯一的过滤索引CREATE UNIQUE INDEX ix ON T(a,b,c) WHERE c <> ''
。在处理并发时,这可能会提高性能并避免潜在的逻辑问题。
INSTEAD OF
除非您想替换实际的插入或更新,否则您可能不需要触发器。在您的情况下,您需要一个FOR INSERT, UPDATE
触发器。
当有人尝试在titles 表中添加或更改数据时,此示例触发器会向客户端打印一条消息。
USE pubs
IF EXISTS (SELECT name FROM sysobjects
WHERE name = 'reminder' AND type = 'TR')
DROP TRIGGER reminder
GO
CREATE TRIGGER reminder
ON titles
FOR INSERT, UPDATE
AS RAISERROR ('inserts and updates to the titles table is not allowed', 16, 1)
GO
你也可以使用类似IF EXISTS
或COLUMNS_UPDATED
的东西。
这是另一个使用回滚的示例。
USE pubs
IF EXISTS (SELECT name FROM sysobjects
WHERE name = 'employee_insupd' AND type = 'TR')
DROP TRIGGER employee_insupd
GO
CREATE TRIGGER employee_insupd
ON employee
FOR INSERT, UPDATE
AS
/* Get the range of level for this job type from the jobs table. */
DECLARE @min_lvl tinyint,
@max_lvl tinyint,
@emp_lvl tinyint,
@job_id smallint
SELECT @min_lvl = min_lvl,
@max_lvl = max_lvl,
@emp_lvl = i.job_lvl,
@job_id = i.job_id
FROM employee e INNER JOIN inserted i ON e.emp_id = i.emp_id
JOIN jobs j ON j.job_id = i.job_id
IF (@job_id = 1) and (@emp_lvl <> 10)
BEGIN
RAISERROR ('Job id 1 expects the default level of 10.', 16, 1)
ROLLBACK TRANSACTION
END
ELSE
IF NOT (@emp_lvl BETWEEN @min_lvl AND @max_lvl)
BEGIN
RAISERROR ('The level for job_id:%d should be between %d and %d.',
16, 1, @job_id, @min_lvl, @max_lvl)
ROLLBACK TRANSACTION
END
我不确定您是否有交易,但在您的情况下,您需要以下内容:
USE myDatabase
IF EXISTS (SELECT name FROM sysobjects
WHERE name = 'myTable' AND type = 'TR')
DROP TRIGGER tr_myTrigger
GO
CREATE TRIGGER tr_myTrigger
ON myTable
FOR INSERT, UPDATE
AS
if(exists(select * from inserted where rtrim(c) <> ''))
begin
-- check to make sure the insert(s) are unique
if(exists(
select * from inserted i
join dbo.myTable t on i.a = t.a and i.b = t.b and i.c = t.c)
begin
raiserror('Duplicate(s) found', 16, 1)
rollback transaction
end
end