在 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_log
、EXTRACT.SEQ_ERROR_LOG
、EXTRACT.SEQ_error_log
、extract.SeQ_ErRoR_lOg
、或者你喜欢的任何东西。您在现有触发器代码中使用它的方式也将起作用。
就我个人而言,我倾向于使用小写 - 但我建议无论您选择什么,您仍然始终如一地使用它,因为编码风格使代码更易于阅读和维护。
我以用户 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_log
、EXTRACT.SEQ_ERROR_LOG
、EXTRACT.SEQ_error_log
、extract.SeQ_ErRoR_lOg
、或者你喜欢的任何东西。您在现有触发器代码中使用它的方式也将起作用。
就我个人而言,我倾向于使用小写 - 但我建议无论您选择什么,您仍然始终如一地使用它,因为编码风格使代码更易于阅读和维护。