用触发器替换唯一约束

时间:2014-12-11 21:01:03

标签: sql triggers db2

我需要用触发器替换唯一约束,但我发现了一个问题(我使用DB2)。 我们假设我有一个带有属性A整数的表R.我定义了这个触发器(类似于更新):

CREATE TRIGGER R_A_UNIQUE
BEFORE INSERT ON R
REFERENCING NEW AS N
FOR EACH ROW
WHEN (EXISTS(SELECT * FROM R WHERE A = N.A))
SIGNAL SQLSTATE '70000' ('ATTRIBUTE A MUST BE UNIQUE');

它在正常情况下有效,但是如果添加多行:

INSERT INTO R VALUES (4),(4),(4);

插入所有值都没有问题!

我错过了什么吗?非常感谢你

2 个答案:

答案 0 :(得分:1)

评论太长了。

insert是一项交易。因此,表的状态在插入过程中不会改变。也就是说,触发器被调用但是在表的原始版本上,都是三次。

这使得难以在触发器内实现类似于唯一约束的东西,并且可以同时处理多个插入。我的建议是坚持使用唯一约束,而不是尝试在触发器中重现它。

我应该补充一点,你可以通过使用“after insert”触发器来改变触发器的语义。但是,这将允许重复项进入表中,然后您必须在之后删除它们。

答案 1 :(得分:0)

您在上面的评论中指出,使用触发器而不是唯一约束的原因是“在DB2中,如果允许空值,则无法将属性定义为唯一”。

根据我所读到的,DB2将在Nullable列上允许“唯一索引”,但不允许在可空列上使用“唯一约束”。

另一个问题是,默认情况下,DB2只允许在单个列的唯一索引中使用一个NULL值,并将2个NULL值视为违反唯一索引。

您可以使用本文中提到的模式(https://www.ibm.com/developerworks/community/blogs/SQLTips4DB2LUW/entry/unique_where_not_null_indexes26?lang=en),通过对允许NULL的列使用生成列来解决此问题并仍使用唯一索引

  

需要的是一个额外的列,它使所有NULL键都是唯一的   如果存在任何NULL,则不会干扰唯一性强制   键中的列

步骤:

1)更改表R以添加生成的列,该列将使NULL值在索引中被视为唯一。

ALTER TABLE R 
ADD A_UNQKEY INT GENERATED ALWAYS AS (CASE WHEN A IS NULL THEN pk ELSE NULL END))

...其中pk是表r的主要关键字。另请注意,您可能需要将数据类型从INT更改为主键的任何类型。

2)在aa_unqkey列上创建唯一索引。

CREATE UNIQUE INDEX UIX_R_A ON R(a, a_unqkey);

现在,表R中的值示例:

pk, a, a_unqkey
1, NULL, 1
2, 'value1', NULL
3, 'value2', NULL
4, NULL, 4

如果没有a_unqkey字段,则列a上的唯一索引将如下所示:

NULL
'value1'
'value2'
NULL   <<**VIOLATES UNIQUE INDEX b/c DUPLICATE OF NULL FROM ROW 1**

但是,如果您在R(a, a_unqkey)上创建唯一索引,那么它将使用以下值:

NULL, 1
'value1', NULL
'value2', NULL
NULL, 4  <<Still unique b/c the other pair is NULL, 1