【问题标题】:How to create an Oracle audit trigger?如何创建 Oracle 审计触发器?
【发布时间】:2018-11-03 22:06:44
【问题描述】:
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 或更少的差评,他们的航程详细信息(客户姓名、游轮名称和日期、船名和评估)但我收到错误

警告:触发器创建时出现编译错误。

审计表是空的,显示没有选择行。我似乎无法找到我出错的问题。

【问题讨论】:

  • 只需在会话中输入show errors 或运行select * from user_errors;看起来很明显的错误是 1)您使用的是没有 into 子句的普通选择(第一个选择),这在 PL/SQL 中是不允许的。 2) 我没有看到声明的变量EVALUATIONAUDIT。摆脱选择,因为无论如何您都没有使用它。
  • 无论您使用什么工具来开发 PL/SQL 代码,您确实需要了解如何使用它来显示编译错误,否则这将继续具有挑战性。如果这是 SQL*Plus,则在编译后立即使用 show errors,或者 show errors trigger evaluation(其中 evaluation 是触发器的名称)。提供更多功能齐全的 IDE。
  • 在上面我发现了错误并把它放在上面,但我不知道我哪里出错了。
  • 您的booking 表没有这些列。
  • 这些列来自 3 个表,如果预订评估小于 2 个,我想在审计表中输入这些表是客户表、船表和航次表。

标签: sql oracle triggers oracle12c database-trigger


【解决方案1】:

也许下面的代码 sn-ps 会对你有所帮助。假设我们有 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 

【讨论】:

  • 我也在使用另外两个表,所以我需要执行 select into 语句并为字段声明一个变量吗?
猜你喜欢
  • 2012-08-14
  • 1970-01-01
  • 1970-01-01
  • 2020-04-18
  • 2021-05-20
  • 2021-06-22
  • 2018-10-24
  • 1970-01-01
相关资源
最近更新 更多