如何制作像主键约束的触发器?

时间:2013-07-12 07:35:58

标签: oracle plsql

我需要定义一个触发器,我想在一列表上应用。触发器应限制用户输入重复值而不是空值。或者你可以说,我需要知道主键的逻辑。

3 个答案:

答案 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约束放在列上。

相关问题