暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle 复合触发器内的DML操作

askTom 2016-11-20
240

问题描述

建议我使用复合触发器,请找到要求和下面的代码。

1、如果是Delete ,则不能删除表中创建的任何记录。
如果试图从该表中删除记录,则会捕获到,请在“审计”表中创建一个条目。
2.如果INSERTING ,则必填字段为ID,LOGIN_USER

•在插入到表中之前,请验证不存在具有相同的LOGIN_USER的现有记录
且记录状态为True。

•如果此验证失败,则返回错误代码和指示失败的消息。

•当将记录插入到表中时,事件后触发器将触发更新下列内容
字段: ID ,包括序列、创建的当前日期/时间和操作“记录插入”
3、如果UPDING ,必填字段为ID,LOGIN_USER

•更新表中的记录时,将触发事件后触发器执行以下操作:

o在影响表中插入记录,复制字段的当前值。

o字段ID、STATUS、LOGIN_USER用给定值填充或覆盖

•将触发事件前触发器,并防止更新不活动的记录。


问题是:
1、在DELETE过程中,我得到了预期的错误,但没有在审计表中插入条目。
2.在INSERT过程中, fire_on_插入的值为TRUE。
3.在更新期间,当我更新时,它将无限期地运行qquery。

请建议最后的代码,因为我没有时间了。这是我第一次使用复合触发器。

创建或替换触发器CMP_TIG
用于删除、插入或更新ID、NUM、登录用户T1
复合触发器

类型t_DBLOGIN是T %RowTYPE ;的表
v_DBLOGON t_DBLOGIN := t_DBLOGIN() ;
I号: =0 ;
V_LOGIN_USER编号;
类型t_审核IS表的审核_TAB %OTYPE ;
v_审计t_审计:= t_审计() ;
j编号:=0 ;

之前语句为
开始
dbms_输出.put_line ('In before语句') ;
语句前结束;

每行之前为
开始
v_audit.extend(1000) ;
v_DBLOGON.extend(1000) ;
如果删除,则
DBMS_OUTPUT.PUT_line ('删除前') ;
j := j+1 ;
v_Audiit(j).ID :=审计_SEQ.NEXTVAL ;
v_Audit(j).操作:='记录删除';
v_审计(j).OBJECTS :='T1';
v_audit(j).IP_AddR := SYS_CONTEXT ('用户V','IP_地址') ;
v_audit(j).DB_LOGIN := SYS.LOGIN_USER ;
v_audit(j).OS_USER := SYS_CONTEXT ('用户V','OS_USER') ;
v_审计(j)。创建的:=系统日期;
结束IF; --关闭IF以便删除

如果插入,则
IF INSERT_FLAG.fire_on_插入='真',然后
从T1选择计数(1)到V_LOGIN_USER
其中: LOGIN_USER = :新.LOGIN_USER AND STAUTS='真';

如果(V_LOGIN_USER>=1) ,则
ALE_APPY_错误( -20002,'数据库登录用户已存在', TRUE ) ;
结束IF ;
I:=I+1 ;
v_DBLOGON(I).ID := DB_SEQ.NEXTVAL ;
v_DBLOGON(I)。创建: =SYSD ;
v_DBLOGON(I).CREED_BY :=用户;
v_DBLOGON(I).事件:='记录插入';
结束IF ;
结束如果; --关闭如果插入

如果正在更新,则
if :old.status ='非活动',然后
错误(-20002,'不能更新无效记录',真) ;
结束IF ;
I := I+1 ;
v_DBLOGON(I).ID := DB_SEQ.NEXTVAL ;
v_DBLOGON(I).STATUS :='False';
v_DBLOGON(I).LOGIN_USER :=:旧.LOGIN_USER ;
结束IF ;

每行前结束;

语句后为
开始
如果删除,则
forall 1..v_audit.count()中的J
插入到审计_TAB值v_Audit(J)中;
ASTED_APLY_错误(-20002,'DBLOGIN_USER_INFO表数据不能删除', TRUE ) ;
结束IF ;

如果插入,则
Forall I in 1..v_DBLOGON.count()
插入T1值v_DBLOGON(I) ;
结束IF ;

如果正在更新,则
INSERT_FLAG.fire_on_插入:='False';
对于1..v_DBLOGON.count()中的所有I
插入T1值v_DBLOGON(I) ;
INSERT_FLAG.fire_on_插入:='true';
结束IF ;
语句后结束;

CMP_TIG结束;
/

专家解答

干得好-你已经很接近了。下面是我的代码,使用的是精简版本的表,但要求是相同的,即

插入=>填充其他列(已创建等)
更新=>保留上一行的副本
不允许删除=>,保留对尝试的审核

我给包添加了一个进程,用于处理自动的东西。


SQL> drop table t1 purge;

Table dropped.

SQL> create table t1 ( x int ,y int, created date, created_by varchar2(10));

Table created.

SQL>
SQL> drop table audit_tab purge;

Table dropped.

SQL> create table audit_tab ( action varchar2(10), who varchar2(20), dte date, x int ,y int);

Table created.

SQL>
SQL>
SQL> create or replace
  2  package audit_pkg is
  3    type t_dblogin is table of t1%rowtype index by pls_integer;
  4    type t_audit is table of audit_tab%rowtype index by pls_integer;
  5
  6    fire_on_insert boolean := true;
  7
  8    procedure delete_separate_transaction(p_audit t_audit);
  9  end;
 10  /

Package created.

SQL>
SQL> create or replace
  2  package body audit_pkg is
  3    procedure delete_separate_transaction(p_audit t_audit) is
  4      pragma autonomous_transaction;
  5    begin
  6
  7      forall j in 1..p_audit.count()
  8        insert into audit_tab values p_audit(j);
  9      commit;
 10    end;
 11  end;
 12  /

Package body created.

SQL>
SQL> create or replace trigger cmp_trig
  2  for delete or insert or update  on t1
  3  compound trigger
  4
  5    v_dblogon audit_pkg.t_dblogin;
  6    v_audit audit_pkg.t_audit;
  7
  8  before each row is
  9  begin
 10    if deleting then
 11      v_audit(v_audit.count+1).action := 'delete';
 12      v_audit(v_audit.count).who := user;
 13      v_audit(v_audit.count).dte := sysdate;
 14      v_audit(v_audit.count).x := :old.x;
 15      v_audit(v_audit.count).y := :old.y;
 16    end if; --close if for deleting
 17
 18    if inserting then
 19      if audit_pkg.fire_on_insert  then
 20        :new.created :=sysdate;
 21        :new.created_by := user;
 22      end if;
 23    end if; --close if for inserting
 24
 25    if updating then
 26      v_dblogon(v_dblogon.count+1).x := :old.x;
 27      v_dblogon(v_dblogon.count).y := :old.x;
 28      v_dblogon(v_dblogon.count).created := :old.created;
 29      v_dblogon(v_dblogon.count).created_by := :old.created_by;
 30    end if;
 31
 32  end before each row;
 33
 34
 35  after statement is
 36  begin
 37    if deleting then
 38       audit_pkg.delete_separate_transaction(v_audit);
 39       raise_application_error (-20002, 'dblogin_user_info table data can not be deleted', true);
 40    end if;
 41
 42    if updating then
 43      audit_pkg.fire_on_insert := false;
 44        forall i in 1..v_dblogon.count()
 45          insert into t1 values v_dblogon(i);
 46      audit_pkg.fire_on_insert := true;
 47    end if;
 48  end after statement;
 49
 50  end cmp_trig;
 51
 52  /

Trigger created.

SQL> sho err
No errors.
SQL>
SQL>
SQL> insert into t1  ( x , y ) values (1,2);

1 row created.

SQL> select * from t1;

         X          Y CREATED   CREATED_BY
---------- ---------- --------- ----------
         1          2 21-NOV-16 MCDONAC

1 row selected.

SQL> select * from audit_tab;

no rows selected

SQL>
SQL> insert into t1  ( x , y ) values (3,4);

1 row created.

SQL> select * from t1;

         X          Y CREATED   CREATED_BY
---------- ---------- --------- ----------
         1          2 21-NOV-16 MCDONAC
         3          4 21-NOV-16 MCDONAC

2 rows selected.

SQL> select * from audit_tab;

no rows selected

SQL>
SQL> update t1
  2  set y = 5
  3  where x = 1;

1 row updated.

SQL> select * from t1;

         X          Y CREATED   CREATED_BY
---------- ---------- --------- ----------
         1          5 21-NOV-16 MCDONAC
         3          4 21-NOV-16 MCDONAC
         1          1 21-NOV-16 MCDONAC

3 rows selected.

SQL> select * from audit_tab;

no rows selected

SQL>
SQL> delete from t1
  2  where x = 3;
delete from t1
            *
ERROR at line 1:
ORA-20002: dblogin_user_info table data can not be deleted
ORA-06512: at "MCDONAC.CMP_TRIG", line 37
ORA-04088: error during execution of trigger 'MCDONAC.CMP_TRIG'


SQL> select * from t1;

         X          Y CREATED   CREATED_BY
---------- ---------- --------- ----------
         1          5 21-NOV-16 MCDONAC
         3          4 21-NOV-16 MCDONAC
         1          1 21-NOV-16 MCDONAC

3 rows selected.

SQL> select * from audit_tab;

ACTION     WHO                  DTE                X          Y
---------- -------------------- --------- ---------- ----------
delete     MCDONAC              21-NOV-16          3          4

1 row selected.

SQL>
SQL>



为您练习-确保在发生错误时重置标志,以便插入标志永远不会被错误地*打开。
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论