在 PL/SQL 中创建触发器抛出编译错误

Creating trigger throwing compilation error in PL/SQL

我以用户 ADMIN 身份登录并执行 PROCEDURE P1 以检查和捕获日志。我在创建触发器时遇到错误

PROCEDURE P1
IS
BEGIN
INSERT statement
BEGIN
---
EXCEPTION

WHEN others THEN
  error_mgr.record_error();
 END P1;

AS ADMIN 用户没有足够的权限我以另一个用户身份登录 EXTRACT 并创建了包 error_mgr

create or replace
PACKAGE BODY error_mgr
IS
PROCEDURE record_error
 IS
 PRAGMA AUTONOMOUS_TRANSACTION;
 l_code  INTEGER := SQLCODE;
 l_mesg VARCHAR2(32767) := SQLERRM; 
 BEGIN
 INSERT INTO EXTRACT.error_log 
(created_on,created_by,errorcode,callstack,errorstack,backtrace,error_info) 
 VALUES(SYSDATE,USER,l_code,sys.DBMS_UTILITY.format_call_stack,null,
  sys.DBMS_UTILITY.format_error_backtrace,l_mesg);
        DBMS_OUTPUT.PUT_LINE('ERROR!!');  
COMMIT;
END record_error;
END error_mgr;

注意:EXTRACT 也是用户名和架构

ERROR LOG table 在提取模式中有一个自动生成的列 id(LOG_ID) 所以在提取模式中我使用序列和触发器

  SEQUENCE:
   CREATE SEQUENCE "EXTRACT"."SEQ_error_log" MINVALUE 1 MAXVALUE 
  9999999999999999999999999999 INCREMENT BY 1 START WITH 335 CACHE 20 NOORDER 
CYCLE ;

触发:

 CREATE TRIGGER EXTRACT.BI_error_log
 BEFORE INSERT ON INO_EIR_EXTRACT.error_log
 REFERENCING NEW AS NEW OLD AS OLD
 FOR EACH ROW

 BEGIN
 -- Set column from sequence
 If (:NEW.LOG_ID IS NULL)
 THEN
  SELECT EXTRACT.SEQ_error_log.NEXTVAL INTO :NEW.LOG_ID FROM dual;
 END IF;
 END;

错误:

PL/SQL:SQL statement ignored
PL/SQL: ORA2289 sequence does not exist.

虽然我已经执行了序列,但我仍然收到这个错误。

您已经创建了序列 with a quoted identifier:当您使用像 SEQ_error_log 这样的不带引号的引用时,Oracle 在数据字典中查找全大写的名称 'SEQ_ERROR_LOG'。但是您将其创建为

CREATE SEQUENCE "EXTRACT"."SEQ_error_log"

这意味着它出现在数据字典中完全一样,没有匹配大写版本的东西,并且无论何时使用它都必须使用带引号的标识符,名称大小写完全相同:

If (:NEW.LOG_ID IS NULL)
THEN
  SELECT EXTRACT."SEQ_error_log".NEXTVAL INTO :NEW.LOG_ID FROM dual;
END IF;

或更简单地说:

If (:NEW.LOG_ID IS NULL)
THEN
  :NEW.LOG_ID := EXTRACT."SEQ_error_log".NEXTVAL;
END IF;

如果您还没有使用它的值填充任何 table 行或者知道如何调整它的起始值来补偿,那么在长 运行 中重新创建序列会更好, 没有带引号的标识符:

DROP SEQUENCE "EXTRACT"."SEQ_error_log";
CREATE SEQUENCE "EXTRACT"."SEQ_ERROR_LOG" START WITH 335;

现在,显然我仍然在标识符周围加上了双引号,但是因为实际名称都是大写且合法的(请参阅开头的文档 link),这等同于说:

CREATE SEQUENCE extract.seq_error_log START WITH 335;

无论哪种方式,序列都可以被引用为大写或不带引号的任何大小写 - extract.seq_error_logEXTRACT.SEQ_ERROR_LOGEXTRACT.SEQ_error_logextract.SeQ_ErRoR_lOg、或者你喜欢的任何东西。您在现有触发器代码中使用它的方式也将起作用。

就我个人而言,我倾向于使用小写 - 但我建议无论您选择什么,您仍然始终如一地使用它,因为编码风格使代码更易于阅读和维护。