Oracle回顾--触发器

Oracle触发器详解与实践

昨天看完了触发器,今天再来写写博客,这样,我又可以复习一下啦……挺好的……

触发器是建立在某个具体的表上的,且触发器在某些事件发生时,由Oracle自动执行,触发器的执行对应用来说是透明的。


一、事件主要有以下几种类型:

1、在指定表/视图中的DML操作:update,delete,insert

2、DDL操作:create ,alter,drop,用于审核和控制数据库操作

3、系统和用户数据库事件:

            用户的登录或注销

            数据库的打开或关闭

            特定的错误消息等


二、触发器的类型:

1、DML触发器(行级触发器、语句级触发器)

        语句级触发器不管执行的语句影响了几行,或者没有影响任何行,这个触发器都会在触发谓词为真时,触发一次该触发器。

        行级触发器执行的次数等于受DML操作影响的数据行数,若没有影响任何一行数据,则不触发。

2、DDL触发器

3、instead of 触发器:用于对多源表的视图进行DML操作,因为多源表的视图本身不能进行DML操作。

4、复合触发器

5、系统和用户事件触发器

可以为表创建before、after 类型的触发器,不能为视图创建before、after类的触发器,只有instead of类型的触发器可以建立在视图上。没有在select类型上的触发器。


三、创建DML触发器:

create  [ or replace ]  trigger 触发器名称

before | after | instead of                              --------------------------------触发类型,同时满足时用or分隔

delete | insert | update [of 列名]                  --------------------------------触发事件

on 表名                                                            --------------------------------作用对象

[for each row [when 条件 ]  ]                        --------------------------------带条件行级触发器的标识,,,用于对表进行修改时,保存修改前的数据,即保存历史数据。

begin

          PL/SQL语句;                                     --------------------------------触发器执行的操作

end;


eg:

create or replace trigger row _del_tr

after

delete

on customernew

for each row when(OLD.customer_name='ANNA')        ------------设置条件。OLD,表示在执行语句外,引用原值,条件必须用圆括号括起,当删除行的customer_name='ANNA‘时才触发触发器

begin

        dbms_output.put_line(’表customernew的1行已经被删除');

end;



Oracle中的触发器谓词有三种,INSERTING,UPDATING,DELETING.通过谓词,用户可以知道对表进行的DML操作的记录,谓词实际是一个布尔值,在触发器内部根据激活动作,会重新赋值。


四、行触发器的变量引用:

关联行:new 、old 分别表示触发器被激活时,当前行新数据和原数据。

new 表示修改后的行,通过new可以引用新行中的各列的值。如   new.cust_firtst_name,

old 表示修改前的行,通过old可以引用原来列的值,如   old.cust_first_name.

在触发器的可执行代码中,要通过old,new引用某列的值,在前面加上":",在insert命令上old没有意义,new表示新插入的行,在delete命令上,new没有意义,old表示被删除的一行。


-----------------------------将对表进行的DML操作,加入到表中,形成历史记录--------------------------------------------

create or replace trigger tr_ca_history

before

update or delete

on categories

for each row

begin

           insert into categories_history values(:old.category_name,:old.category_description,:old.category_id,sysdate);

end;


----------------------------------------------将插入值的某列转为大写-----------------------------------------------------------------

create or replace trigger tr_cus_upper

before

update or insert

on customernew

for each row

begin

         :new.status :=upper(:new.status);

end;

在触发器内部使用:new变量时,触发动作不能包括delete操作,创建行触发器为列赋值,通过:new更改列的值,即使update中未涉及到该列,数据表中该列的值也会被修改,不能修改old引用的值。


五、变量引用与referencing,

referencing主要用于为new ,old起别名

-----------------------取最大编号加1作为新插入数据的编号-------------------------------------

create or replace trigger tr_cus_insert

before

insert

on customernew

referencing new as new_value

for each row

begin

        declare

              max_id number;

        begin

              select max(customer_id) into max_id from customernew;

              :new_value :=max_id+1;

        end;

end;

六、instead of 触发器

instead of 触发器定义在视图上,用来替换实际的操作语句,该类型的触发开阔地可以帮助用户实现更新视图所属的源表,语法与之前的一样,"instead of “ 的意思是当在视图上进行DML操作时,不去执行指定的是DML语句,而是执行触妇器的代码。

视图上的触发器都是行触发器,因此,在建触发器时for each row 可以省略,受影响的每一行数据都会激发触发器一次,可以用关联行old,new

eg:

create or replace trigger tr_cus_view

instead of

delete or update

on view_cus            -------------视图上的触发器都是行触发器,因此,在建触发器时,for each row可以省略,受影响的每一行数据都会激发触发器一次,可以用关联行old,new

for each row

begin

         if deleting then

               if :old.status = 'gold' then

                     raise_application_error(-20001,'gold顾客不能删除');                ---------------------------给出错误提示

              end if;

        end if;

        if updating then

            if :new.credit_limit <= :old.credit_limit then

                  raise_application_error(-20002,'赊销限额不能减少');

             end if;

         end if;

end;


-------------------------在有多个数据源的视图中,执行update或delete操作是不允许的,可以利用触发器转化另外的SQL语句执行达到效果。------------------------------------

-------------insert into vw_order_cus values(2459,sysdate,117,'guillaume');-------------视图源于customernew表和orders表

create or replace trigger tr_view

instead of

update or delete or insert

on vw_order_cus

for each row

begin

            if inserting then

                      insert into orders(order_id,order_date,customer_id) values(:new.order_id,:new.order_date,:new.customer_id);

            end if;

            if deleting then

                      delete from orders where order_id = :old.order_id;

            end if;

end;

在视图上进行DML操作还要遵守基表上的完整性约束。


七、DDL触发器

sysevent取到当前操作的类型。

if sysevent = 'drop ' then      -------- 如果事件类型为drop

       if dictionary_obj_name = 'cus_log' then    -------------数据字典对象名

on schema

八、系统事件触发器

oracle中的系统事件:

       startup                            数据库打开后触发,模式下不可以

       shutdown                       数据库关闭前触发,模式下不可以

       logon                              客户程序登陆后触发

       logoff                              客户程序登录前触发

       servererror                     错误消息出现后触发

create or replace trigger tr_db_log

before

shutdown

on database

begin

              insert into database_log values(user,'shutdown',sysdate);               ----------------------user,当前用户

end;

九,

一个用户可以拥有数据库中的多个对象,用户事件触发器的作用对象不是单个对象,而是用户所拥有的所有对象的集合,即常说的schema,以下逡的before,after时机均可创触发器:

alter:修改对象属性

analyze:分析数据瑶的统计信息,以供优化器使用

associate statistics:关联统计信息

audit:开启对象或系统上的审计功能,以便记录和跟踪用户操作

comment:为表或列添加注释,这些注释可以通过数据字典获取,

create:创建对象

disassociate statistics:取消统计信息的关联

drop:删除对象

grant:为数据库用户授予权限或角色

noaudit:关闭对象或系统上的审计功能

rename:重命名数据库中的对象

revoke:收回数据库用户的权限或角色

truncate:删除表中所有的记录,并且不能回滚

以下事件只有after触发器:

suspend:当程序运行出现错误,并导致程序挂起。

create or replace trigger tr_truncate_table

after

truncate

on system.schema              --------------作用对象为用户system的所有对象

begin

            insert into truncate_log values(ora_dic_obj_name,user,sysdate);     ----------------ora_dic_obj_name 被删除对象的对象名称(被删除记录的表名),user,当前用户

end;


十、与触发器相关的视图(数据字典)

user_triggers:存储当前用户所拥有的触发器

dba_triggers:存储管理员所拥有的触发器

all_triggers:存储所有的触发器

user_objects:存储当前用户所拥有的对象,包括触发器

dba_objects:存储管理员所拥有的对象,包括触发器

all_objects:存储数据库中所有的对象,包括触发器

select trigger_name(触发器名),trigger_type(触发器类型,before/after....),triggering_event(触发事件),table_name(表名),trigger_body(执行块),status(状态) from user_triggers where lower(trigger_name)='del_tri';

十一、启用/禁用触发器

alter trigger 触发器名 enable/disable


<think>好的,我现在需要解决用户提出的关于Oracle数据库ORA-00001错误的问题。首先,我得回顾一下用户提供的引用内容,看看有哪些相关信息。用户引用了四个资料,主要涉及序列问题、资源忙、数据库启动问题以及具体的解决步骤。 ORA-00001错误通常是因为违反了唯一约束,也就是插入了重复的值到有唯一索引的列中。根据引用[1][3],可能的原因之一是序列(sequence)的当前值小于表中已有数据的最大值,导致插入时生成的主键重复。比如,当序列的最小值设置得太低,或者没有正确设置起始值,就可能出现这种情况。解决方法包括调整序列的当前值,使其超过表中的最大值。 另外,引用[4]提供了一个具体的解决步骤,包括查询约束对应的表字段,检查序列的下一个值,修改序列的步长以快速跳过当前值,然后再恢复步长。这应该是一个标准的处理流程。 还有可能用户插入的数据中有重复的值,而不仅仅是主键的问题。例如,业务字段本身有唯一约束,但应用程序没有正确处理重复数据的情况。这时候需要检查数据来源,或者添加唯一性校验。 引用[2]提到了ORA-00054资源正忙的错误,这可能当前的问题无关,但用户可能之前遇到多个错误,需要注意区分。不过用户现在明确询问的是ORA-00001,所以重点应放在唯一约束上。 接下来,我需要将这些原因解决方法结构化,分点说明。同时,需要确保回答清晰,步骤明确,帮助用户逐步排查问题。可能的原因有:主键或唯一约束字段重复插入、序列配置问题、并发插入导致的问题等。解决方案包括检查重复数据、调整序列、处理并发等。 还需要注意引用对应的资料,比如在序列问题时引用[1]、[3]、[4],在检查重复数据时引用[4]的步骤。可能用户需要具体的SQL语句来执行这些检查,比如查询约束信息、修改序列等。 此外,用户可能需要知道如何避免此类问题,比如在应用层处理唯一性校验,或者在设计表时合理设置序列的初始值缓存大小。 最后,生成相关问题,帮助用户进一步理解可能相关的其他问题,比如如何调整序列、如何查找违反约束的数据等。</think>### ORA-00001 违反唯一约束条件的解决方案 #### 错误原因分析 1. **主键/唯一约束字段重复插入** - 插入数据时违反了表中已定义的主键或唯一性约束,可能是手动指定了重复值,或序列生成值重复[^1][^3]。 - **示例场景**:表中已存在 `ID=100` 的记录,再次插入相同值会触发此错误。 2. **序列(Sequence)配置不当** - 序列的当前值(`CURRVAL`)小于表中对应字段的最大值,导致生成重复键[^1][^3][^4]。 - **典型表现**:序列从 `START WITH 1` 开始,但表中已有 `ID=200` 的记录。 3. **并发插入导致冲突** - 多线程/多会话环境下,序列的缓存机制(`CACHE`)可能生成重复值[^3]。 --- #### 分步解决方案 ##### 步骤1:定位违反约束的字段表 ```sql -- 替换约束名称 SYS_C0024492 SELECT a.constraint_name, a.constraint_type, b.column_name, b.table_name FROM user_constraints a JOIN user_cons_columns b ON a.table_name = b.table_name WHERE a.constraint_name = 'SYS_C0024492'; ``` 通过查询确定具体违反约束的表字段[^4]。 --- ##### 步骤2:检查序列与数据表状态 1. **查询序列当前值** ```sql -- 替换序列名称 S_RECORDID SELECT sequence_name, last_number FROM user_sequences WHERE sequence_name = 'S_RECORDID'; ``` 2. **查询表中字段最大值** ```sql -- 替换字段名 RECID 表名 m_Operrecord_Ht SELECT MAX(RECID) FROM m_Operrecord_Ht; ``` 如果序列的 `last_number` 小于表中字段的最大值,需修正序列[^4]。 --- ##### 步骤3:修正序列值 ```sql -- 1. 修改序列步长(假设当前差值为200) ALTER SEQUENCE S_RECORDID INCREMENT BY 200; -- 2. 触发一次序列获取新值 SELECT S_RECORDID.NEXTVAL FROM dual; -- 3. 恢复步长为1 ALTER SEQUENCE S_RECORDID INCREMENT BY 1; ``` 通过临时调整步长快速跳过冲突值[^4]。 --- ##### 步骤4:检查重复数据 如果错误由业务字段(非序列生成字段)引起: ```sql -- 替换字段名表名 SELECT your_column, COUNT(*) FROM your_table GROUP BY your_column HAVING COUNT(*) > 1; ``` 删除或修改重复数据。 --- ##### 步骤5:优化序列配置 - 设置序列起始值为表字段最大值 +1: ```sql CREATE SEQUENCE SEQ_A START WITH 201; -- 示例值 ``` - 增加缓存大小(需权衡性能与重复风险): ```sql ALTER SEQUENCE SEQ_A CACHE 50; ``` --- #### 预防措施 1. **应用层校验**:插入前检查唯一性。 2. **序列监控**:定期比对序列值与表数据。 3. **使用触发器**(谨慎):在插入前动态修正主键值。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值