2011-05-27 125 views
2

執行一些MSSQL練習,我試圖創建一個觸發器。然而,我的解決方案在理論上對我來說是正確的,但它不起作用。卡在創建觸發器

目標是爲只有兩列的表創建觸發器。一列是主鍵,是標識,不允許空值。另一列是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 

然而,儘管如此,交易執行本身。我不確定爲什麼會發生這種情況,並且觸發器不會自行發射。

那麼有人在這裏啓發我的疑慮嗎?

我也在觸發器開始時使用了set ANSI_WARNINGS OFF。

回答

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) 
+0

工作,非常感謝你! – Parijat 2011-05-27 22:21:34

0

是的,這是一個問題。 COUNT的parens內部的表達式必須評估爲不爲null,否則將不計算。因此,使用*1或表達式中的任何不可空列都更安全。最常遇到的表達方式是'*',但您也可以遇到'1'。這些表達式在性能方面沒有區別。但是,如果您使用可以評估爲空的表達式(如可空列),則您的計數和其他聚合可以完全關閉。

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