如何创建Oracle审计触发器?

时间:2018-05-24 15:47:16

标签: sql oracle triggers oracle12c database-trigger

CREATE OR REPLACE TRIGGER EVALUATION
BEFORE INSERT OR UPDATE OR DELETE ON BOOKING
FOR EACH ROW 
DECLARE 

BEGIN

SELECT BOOKING_EVALUATION FROM BOOKING WHERE BOOKING_EVALUATION > 2;

SELECT BOOKING_EVALUATION INTO EVALUATIONAUDIT FROM BOOKING;


IF INSERTING THEN
INSERT INTO EVALUATIONAUDIT (VOYAGES_ID,CUSTOMER_NAME,START_DATE,SHIP_NAME,BOOKING_EVALUATION)
VALUES(:NEW.VOYAGES_ID,:NEW.CUSTOMER_NAME,:NEW.START_DATE,:NEW.SHIP_NAME,:NEW.BOOKING_EVALUATION);
END IF;


IF UPDATING THEN
INSERT INTO EVALUATIONAUDIT (VOYAGES_ID,CUSTOMER_NAME,START_DATE,SHIP_NAME,BOOKING_EVALUATION)
VALUES(:OLD.VOYAGES_ID,:OLD.CUSTOMER_NAME,:OLD.START_DATE,:OLD.SHIP_NAME,:OLD.BOOKING_EVALUATION);
END IF;


IF DELETING THEN
INSERT INTO EVALUATIONAUDIT (VOYAGES_ID,CUSTOMER_NAME,START_DATE,SHIP_NAME,BOOKING_EVALUATION)
VALUES(:OLD.VOYAGES_ID,:OLD.CUSTOMER_NAME,:OLD.START_DATE,:OLD.SHIP_NAME,:OLD.BOOKING_EVALUATION);
END IF;
END;

这是我的审核表:

desc evaluationaudit;
 Name                                      Null?    Type
 ----------------------------------------- -------- -----------------------

 AUDITT_ID                                 NOT NULL NUMBER(10)
 VOYAGES_ID                                NOT NULL NUMBER(10)
 CUSTOMER_NAME                             NOT NULL VARCHAR2(20)
 START_DATE                                NOT NULL DATE
 SHIP_NAME                                 NOT NULL VARCHAR2(20)
 BOOKING_EVALUATION                        NOT NULL NUMBER(20)

and this is my show error output:
SQL> SHOW ERRORS;
Errors for TRIGGER EVALUATION:

LINE/COL ERROR
-------- -------------------------------------------------------------
12/24    PLS-00049: bad bind variable 'NEW.CUSTOMER_NAME'
12/43    PLS-00049: bad bind variable 'NEW.START_DATE'
12/59    PLS-00049: bad bind variable 'NEW.SHIP_NAME'
18/24    PLS-00049: bad bind variable 'OLD.CUSTOMER_NAME'
18/43    PLS-00049: bad bind variable 'OLD.START_DATE'
18/59    PLS-00049: bad bind variable 'OLD.SHIP_NAME'
24/24    PLS-00049: bad bind variable 'OLD.CUSTOMER_NAME'
24/43    PLS-00049: bad bind variable 'OLD.START_DATE'
24/59    PLS-00049: bad bind variable 'OLD.SHIP_NAME'

我想添加到审计表中。如果客户评价为2或更低,他们的航程详情(客户名称,邮轮的名称和日期,船名和评估),但我收到错误

  

警告:使用编译错误创建触发器。

审计表为空,表示未选择任何行。我似乎无法找到问题所在。

1 个答案:

答案 0 :(得分:2)

以下代码段可能会对您有所帮助。假设我们有2个表:BOOKING和EVALUATION_AUDIT(用大写字母写的所有内容都取自你问题中的代码)。

<强>表格

create table booking (
  VOYAGES_ID number primary key
, CUSTOMER_NAME  VARCHAR2(20) NOT NULL 
, START_DATE     DATE         NOT NULL
, SHIP_NAME      VARCHAR2(20) NOT NULL 
, BOOKING_EVALUATION NUMBER(20) NOT NULL
) ;

create table evaluationaudit (
  AUDITT_ID number generated always as identity start with 5000 primary key
, trg_cond_pred  varchar2( 64 ) default 'Row not added by evaluation trigger!'
, VOYAGES_ID     NUMBER(10)                 NOT NULL
, CUSTOMER_NAME  VARCHAR2(20)               NOT NULL
, START_DATE     DATE                       NOT NULL
, SHIP_NAME      VARCHAR2(20)               NOT NULL 
, BOOKING_EVALUATION  NUMBER(20)            NOT NULL
) ; 

<强>触发

   -- "updating" and "deleting" code omitted for clarity 
   CREATE OR REPLACE TRIGGER EVALUATION_trigger
      BEFORE INSERT OR UPDATE OR DELETE ON BOOKING
      FOR EACH ROW 
   BEGIN
     case
       when INSERTING then
         if :new.booking_evaluation <= 2 then
           INSERT INTO EVALUATIONAUDIT 
           ( trg_cond_pred,
             VOYAGES_ID, CUSTOMER_NAME, START_DATE, SHIP_NAME, BOOKING_EVALUATION )
           VALUES (
               'INSERTING'
             , :NEW.VOYAGES_ID
             , :NEW.CUSTOMER_NAME
             , :NEW.START_DATE
             , :NEW.SHIP_NAME
             , :NEW.BOOKING_EVALUATION
           );
        end if ;
      end case ;
    END ;
    /

<强>测试

您的一个要求(在您的问题中)是:

  

我想添加到审计表中。如果客户给穷人   评估2或更少,他们的航程的详细信息(customer_name,   邮轮的名称和日期,船名和评估)

delete from evaluationaudit ;
delete from booking ;

-- booking_evaluation greater than 2 -> no entry in audit table
insert into booking 
( VOYAGES_ID, CUSTOMER_NAME, START_DATE, SHIP_NAME, BOOKING_EVALUATION )
values ( 1111, 'customer1', date '2018-05-24', 'ship1', 9999 ) ;

select * from evaluationaudit ;
-- no rows selected


-- booking_evalution = 2 -> insert a row into the audit table
insert into booking 
( VOYAGES_ID, CUSTOMER_NAME, START_DATE, SHIP_NAME, BOOKING_EVALUATION )
values ( 1112, 'customer1', date '2018-05-24', 'ship1', 2 ) ;

select * from evaluationaudit ;

AUDITT_ID  TRG_COND_PRED  VOYAGES_ID  CUSTOMER_NAME  START_DATE  SHIP_NAME  BOOKING_EVALUATION  
5000       INSERTING      1112        customer1      24-MAY-18   ship1      2   

<强> __更新__

如果 - 正如您在评论中写的那样 - 您需要从其他表中提取更多数据,也许您想尝试以下方法:保持触发器代码相当简短,并使用它来调用更多的过程复杂的东西,例如

<强>表格

create table evaluationaudit (
  AUDITT_ID number generated always as identity start with 7000 primary key
, trg_cond_pred  varchar2( 64 ) default 'Row not added by evaluation trigger!'
, VOYAGES_ID NUMBER               NOT NULL
, CUSTOMER_NAME  VARCHAR2(20)     NOT NULL
, SHIP_NAME      VARCHAR2(20)     NOT NULL 
, BOOKING_EVALUATION  NUMBER(20)  NOT NULL
) ; 

create table ships ( name varchar2( 64 ), id number unique ) ;
create table customers ( name varchar2( 64 ), id number unique ) ;

insert into ships ( name, id ) values ( 'ship1', 501 );
insert into ships ( name, id ) values ( 'ship2', 502 );
insert into ships ( name, id ) values ( 'ship3', 503 );
insert into customers ( name, id ) values ( 'customer1', 771 ) ;
insert into customers ( name, id ) values ( 'customer2', 772 ) ;
insert into customers ( name, id ) values ( 'customer3', 773 ) ;

create table bookings (
  id number generated always as identity start with 5000 primary key
, voyagesid number 
, shipid number
, customerid number
, evaluation number
, bookingdate date
);

<强>触发

create or replace trigger bookingeval
  before insert on bookings
  for each row
  when ( new.evaluation <= 2 ) -- Use NEW without colon here! ( see documentation )
begin
  auditproc( :new.voyagesid, :new.customerid, :new.shipid, :new.evaluation ) ;
end ;
/

<强>程序

create or replace procedure auditproc (
  voyagesid_ number
, customerid_ number
, shipid_ number
, evaluation_ number
)
as  
  customername varchar2( 64 ) := '' ;
  shipname varchar2( 64 ) := '' ;
begin
  -- need to find the customername and shipname before INSERT
  select name into customername from customers where id = customerid_ ;
  select name into shipname from ships where id = shipid_ ;  
  insert into evaluationaudit
  ( trg_cond_pred,
    voyages_id, customer_name, ship_name, booking_evaluation )
  values (
    'INSERTING'
  , voyagesid_
  , customername
  , shipname
  , evaluation_
  );  
end ;
/

<强>测试

-- evaluation > 2 -> no INSERT into evaluationaudit
insert into bookings 
( voyagesid, customerid, shipid, evaluation, bookingdate )
values ( 1111, 771, 501, 9999, sysdate ) ;

select * from evaluationaudit ;
-- no rows selected

-- evaluation = 2 
-- -> trigger calling audit procedure -> inserts into evaluationaudit
insert into bookings 
( voyagesid, customerid, shipid, evaluation, bookingdate )
values ( 1112, 772, 502, 2, sysdate ) ;

select * from evaluationaudit ;

AUDITT_ID  TRG_COND_PRED  VOYAGES_ID  CUSTOMER_NAME  SHIP_NAME  BOOKING_EVALUATION  
7000       INSERTING      1112        customer2      ship2      2