坚持创造一个触发器

时间:2011-05-27 21:41:02

标签: sql-server sql-server-2005

执行一些MSSQL练习,我正在尝试创建一个触发器。但是,我所遇到的解决方案在理论上对我来说是正确的,但它不起作用。

目的是为只有两列的表创建一个触发器。一列是主键,是Identity,不允许空值。另一列是ALLOWS NULL值。但是,它仅允许整个表中的单行的NULL值。基本上,触发器应触发此表上的插入/更新操作,当该表中的列已存在NULL值时,该操作尝试将列插入/更新为NULL值。

我在触发器代码中捕获的这种情况如下:

After Insert, Update
AS 
set ANSI_WARNINGS OFF
If ( (select count(NoDupName) from TestUniqueNulls where NoDupName is null) > 1 )
BEGIN
Print 'There already is a row that contains a NULL value, transaction aborted';
ROLLBACK TRAN
END

但是,事务仍会自行执行。我不确定为什么会发生这种情况并且触发器没有触发。

所以有人在这里启发我的疑虑吗?

我还在触发器的开头使用了设置ANSI_WARNINGS OFF。

2 个答案:

答案 0 :(得分:2)

count(col)仅计算非空值,因此count(NoDupName) ... where NoDupName is null始终为零。您需要检查count(*)

我意识到这只是一种练习练习,但索引视图可能是一种更好的机制。

CREATE VIEW dbo.NoMoreThanOneNull
WITH SCHEMABINDING
AS
SELECT NoDupName
FROM dbo.TestUniqueNulls
WHERE NoDupName IS NULL

GO

CREATE UNIQUE CLUSTERED INDEX ix ON dbo.NoMoreThanOneNull(NoDupName)

答案 1 :(得分:0)

是的,这是一个问题。 COUNT的parens中的表达式必须求值为null,否则不会计算。因此,在表达式中使用*1或任何不可为空的列更安全。最常见的表达式是'*',尽管你也可以遇到'1'。这些表达在性能方面没有区别。但是,如果使用可以计算为null的表达式(如可空列),则可以完全关闭计数和其他聚合。

create table nulltest(a int null)
go
insert nulltest(a) values (1), (null), (2)
go
select * from nulltest
select COUNT(*) from nulltest
select COUNT(1) from nulltest
select COUNT(a) from nulltest
go
drop table nulltest