我正在尝试在表上写一个触发器,以避免插入两个未标记为IsDeleted的Name。但是选择的第一部分包含插入的部分,因此条件始终为真。我虽然使用FOR关键字导致触发器在INSERTION之前运行,但在这种情况下插入的行已经在表中。我错了还是所有FOR触发器都有效?
ALTER TRIGGER TriggerName
ON MyTable
FOR INSERT, UPDATE
AS
BEGIN
If exist (select [Name] From MyTable WHERE IsDeleted = 0 AND [Name] in (SELECT [Name] FROM INSERTED)
BEGIN
RAISERROR ('ERROR Description', 16, 1);
Rollback;
END
END
答案 0 :(得分:2)
FOR数据更改后运行,INSTEAD OF就是我认为您所追求的。
编辑:正如其他人所说,INSTEAD OF运行而不是您正在更改的数据,因此如果数据有效则需要插入数据,而不是在数据无效时停止插入。
阅读此问题以获得有关触发类型的更详细说明。
SQL Server "AFTER INSERT" trigger doesn't see the just-inserted row
答案 1 :(得分:1)
FOR与AFTER相同。如果你想“模拟”BEFORE触发器,使用INSTEAD OF,请注意,这并不是你在正确的BEFORE触发器上所期望的,即如果你未能提供必要的INSTEAD动作,你插入/更新的数据可能会丢失/被忽略。
MSSQL没有BEFORE触发器。
答案 2 :(得分:0)
对于SQL Server,FOR在触发它的SQL之后运行。
自: http://msdn.microsoft.com/en-us/library/ms189799.aspx
FOR | AFTER 强>
AFTER 指定DML触发器 只有在所有操作时才会被触发 在触发SQL中指定 声明已成功执行。 所有参考级联行动和 约束检查也必须成功 在此触发器触发之前。
当FOR为时,AFTER 是默认值 仅指定关键字。
AFTER 触发 无法在视图上定义。
答案 3 :(得分:0)
我最近遇到了类似的问题,并找到了一种很酷的方法来处理它。我有一个表可以为一个id有几行,但只有一行可以标记为主要。
在SQL Server 2008中,您将能够创建类似于此的部分唯一索引:
create unique index IX on MyTable(name) where isDeleted = 0;
但是,您可以在SQL Server 2005中完成更多工作。诀窍是创建一个视图,仅显示未删除的行,然后在其上创建唯一的聚簇索引:
create view MyTableNotDeleted_vw
with schema_binding /* Must be schema bound to create an indexed view */
as
select name
from dbo.MyTable /* Have to use dbo. for schema bound views */
where isDeleted = 0;
GO
create unique clustered index IX on MyTableNotDeleted_vw ( name );
这将有效地创建一个唯一的约束,仅影响尚未删除的行,并且可能比自定义触发器执行得更好!