我需要定义一个触发器,我想在一列表上应用。触发器应限制用户输入重复值而不是空值。或者你可以说,我需要知道主键的逻辑。
答案 0 :(得分:2)
“我想学习,如何制作主键(当然是触发器)”
关于它,当然没有“当然”。约束不是触发器。它是一个内部流程,它使用索引和大量低级活动以可靠和有效的方式强制执行关系约束。
如果你想学习规则是非常简单的:不是null,唯一性,序列化。所以只需尝试在触发器中实现主键。由于“变异表”问题,你会发现你不能(扰乱警报!)。如果你不明白这意味着什么,那么有一个很好的主题可供阅读。
有一个问题“是否无法定义触发器,哪个 在插入之前检查它不应该为null的值 独一无二的? “
这个问题的答案是,不。嗯,您可以编写基于触发器的实现,但与其他“变异表”解决方法一样,它需要一个包和AFTER语句触发器(因此技术上不在插入之前)。
但严重的是,重点是什么?您将无法了解主键如何实际工作。变异表几乎总是指向一个糟糕的数据模型,这肯定就是这种情况。
答案 1 :(得分:2)
只是因为你似乎有意看到这个失败,而不是从APC的观点带走任何东西,只要它是before
触发器,这似乎乍一看:
create table t42 (id number);
create trigger trig42
before insert or update on t42
for each row
declare
c number;
begin
if :new.id is null then
raise_application_error(-20001, 'ID is null');
end if;
select count(*) into c from t42 where id = :new.id;
if c > 0 then
raise_application_error(-20002, 'ID is not unique');
end if;
end;
/
它编译,如果你插入数据,你会得到你想要的行为:
insert into t42 values (1);
1 rows inserted.
insert into t42 values (1);
Error starting at line 20 in command:
insert into t42 values (1)
Error report:
SQL Error: ORA-20002: ID is not unique
ORA-06512: at "STACKOVERFLOW.TRIG42", line 9
ORA-04088: error during execution of trigger 'STACKOVERFLOW.TRIG42'
insert into t42 values (null);
Error starting at line 22 in command:
insert into t42 values (null)
Error report:
SQL Error: ORA-20001: ID is null
ORA-06512: at "STACKOVERFLOW.TRIG42", line 5
ORA-04088: error during execution of trigger 'STACKOVERFLOW.TRIG42'
select * from t42;
ID
----------
1
这似乎做你想要的。但如果你有多个会话,那就没有了。我没有参加这次会议;在另一场我可以做的事情:
insert into t42 values (1);
1 row created.
select * from t42;
ID
----------
1
1 row selected.
嗯,这很奇怪。好吧,也许它被推迟了......让我们两个都承诺:
commit;
select * from t42;
ID
----------
1
1
2 rows selected.
糟糕。一旦会话无法看到另一个会话的未提交数据,那么这将永远不会有效。
此外,当我们在一个语句中插入多行时,变异表问题就会出现:
SQL> insert into t42 select level+1 from dual connect by level <= 5;
insert into t42 select level+1 from dual connect by level <= 5
*
ERROR at line 1:
ORA-04091: table STACKOVERFLOW.T42 is mutating, trigger/function may not see it
ORA-06512: at "STACKOVERFLOW.TRIG42", line 7
ORA-04088: error during execution of trigger 'STACKOVERFLOW.TRIG42'
SQL>
双哟。
即使有一个after
触发器和一个解决变异表问题的包,你仍然会遇到这个问题(我认为),除非你为每个插入或更新锁定整个表。正如APC所说,约束是在数据库的内部深处实现的,而不是在这个级别。
是不可能定义一个触发器,它会检查之前的值 插入它不应该是null并且也是唯一的?
当你有多个会话时,不是。即使在一个会话中,除非您在列上有索引,否则性能将无法扩展,因为count(*)
将逐渐变慢。如果你确实有一个索引,那么为什么不把它作为一个独特的索引呢?
最后,来自trigger design guidelines:
不要创建复制数据库功能的触发器。
例如,如果可以,请不要创建拒绝无效数据的触发器 对约束做同样的事情(参见“How Triggers and Constraints Differ")。
答案 2 :(得分:1)
主键不是触发器。它是一个关键,因为它标识整行,这就是为什么它应该是唯一的(并且隐式地不为空)。它是“主要”,因为根据您的决定,最合适的候选键是您的表的主要参考键。您可以将其添加为ALTER TABLE your_table_name ADD CONSTRAINT PK_your_table_name PRIMARY KEY (your_key_column)
。
如果您不想添加这样的主键(这是一个坏主意),但想要为该表添加唯一索引:CREATE UNIQUE INDEX UQ_IX_your_table_your_column ON your_table_name (unique_column_name)
。
应将NOT NULL
约束放在列上。