我需要用触发器替换唯一约束,但我发现了一个问题(我使用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);
插入所有值都没有问题!
我错过了什么吗?非常感谢你
答案 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)在a
和a_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