Как создать триггер аудита Oracle? - PullRequest
0 голосов
/ 24 мая 2018
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 голосов
/ 24 мая 2018

Может быть, вам помогут следующие фрагменты кода.Предположим, у нас есть 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 или менее, данные его рейса (имя клиента, название и дата круиза, название судна и оценка)

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   

__ Update __

Если - как вы написали в своем комментарии - вам нужно извлечь еще некоторые данные из других таблиц, возможно, вы захотите попробовать следующий подход: сделать код триггера довольно коротким и использовать его для вызовапроцедура для более сложных вещей, например

Таблицы

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 
...