带有动态 sql 的 PL/SQL 触发器

Posted

技术标签:

【中文标题】带有动态 sql 的 PL/SQL 触发器【英文标题】:PL/SQL Triggers with dynamic sql 【发布时间】:2017-06-12 23:05:09 【问题描述】:

我想创建 ddl 触发器(在创建时),它将创建一个 dml 触发器 但我有错误:

ORA-06512:第 8 行 00604. 00000 - “错误发生在递归 SQL 级别 %s” *原因:处理递归 SQL 语句时出错 (适用于内部字典表的语句)。 *Action:如果堆栈中描述的情况下一个错误 可以更正,这样做;否则请联系 Oracle 支持。

CREATE OR REPLACE TRIGGER test_ddl
after CREATE ON SCHEMA
DECLARE 
    user_col VARCHAR(5) := 'user_';
    time_col VARCHAR(5) := 'time_';
BEGIN
IF ora_dict_obj_type = 'TABLE'
THEN 
    EXECUTE IMMEDIATE 'alter table ' || ora_dict_obj_name || ' add(' || user_col || ' varchar(20), '|| time_col ||' timestamp)'||'';
    EXECUTE IMMEDIATE 'CREATE OR REPLACE TRIGGER add_user_time BEFORE INSERT OR UPDATE ON test_tab FOR EACH ROW BEGIN ' || ':' || 'new.time_ := sysdate; END';
END IF;
END;                               
/
DROP TABLE test_tab PURGE;
/
CREATE TABLE test_tab(ID NUMBER);

【问题讨论】:

您可能想要做一些日志记录,至少是正在生成和执行的 DDL 语句。您的触发器创建语句似乎是用触发器和表的单个名称硬编码的——这可能是也可能不是原因。添加记录错误的异常处理程序可能会有所帮助(在重新引发错误之前)。请注意,此触发器将在创建触发器时以递归方式触发(当然,由于 ora_dict_obj_type 的条件,您的代码会停止递归触发器实际执行任何操作)。 【参考方案1】:

至少,我希望您希望 new.time_ 成为 :new.time_

【讨论】:

问题不在此。问题是我无法在其他触发器中创建触发器 是的,我错过了。【参考方案2】:

END 后面缺少一个分号。

替换这个

EXECUTE IMMEDIATE 'CREATE OR REPLACE TRIGGER add_user_time BEFORE INSERT OR UPDATE ON test_tab FOR EACH ROW BEGIN ' || ':' || 'new.time_ := sysdate; END';

这样

EXECUTE IMMEDIATE 'CREATE OR REPLACE TRIGGER add_user_time BEFORE INSERT OR UPDATE ON test_tab FOR EACH ROW BEGIN ' || ':' || 'new.time_ := sysdate; END;';

完整的错误消息是:

ORA-00604: error occurred at recursive SQL level 1
ORA-24344: success with compilation error
ORA-06512: at line 8

重要的部分是:

ORA-24344: success with compilation error

源代码应为:

CREATE OR REPLACE TRIGGER test_ddl
after CREATE ON SCHEMA
DECLARE 
    user_col VARCHAR(5) := 'user_';
    time_col VARCHAR(5) := 'time_';
BEGIN
IF ora_dict_obj_type = 'TABLE'
THEN 
    EXECUTE IMMEDIATE 'alter table ' || ora_dict_obj_name || ' add(' || user_col || ' varchar(20), '|| time_col ||' timestamp)'||'';
    EXECUTE IMMEDIATE 'CREATE OR REPLACE TRIGGER add_user_time BEFORE INSERT OR UPDATE ON test_tab FOR EACH ROW BEGIN ' || ':' || 'new.time_ := sysdate; END;';
END IF;
END;                               
/
DROP TABLE test_tab PURGE;
/
CREATE TABLE test_tab(ID NUMBER);

作为解释:我已经放了一些日志消息来查看它到底在哪里失败了。然后你可以看到触发器被递归调用 CREATE OR REPLACE TRIGGERora_dict_obj_type = TRIGGER

【讨论】:

在 CREATE ON SCHEMA DECLARE user_col VARCHAR(5) 后创建或替换触发器 test_ddl := 'user_'; time_col VARCHAR(5) := 'time_'; BEGIN IF ora_dict_obj_type = 'TABLE' THEN EXECUTE IMMEDIATE 'alter table' || ora_dict_obj_name || ' add(' || user_col || ' varchar(20), '|| time_col ||' 时间戳)'||'';立即执行'创建或替换触发器 add_user_time' || ora_dict_obj_name || ' 在插入或更新之前 ' || ora_dict_obj_name || ' 每行开始 ' || ':' || 'new.time_ := 系统日期;结尾;';万一;结尾; CREATE TABLE test_tab(ID NUMBER);

以上是关于带有动态 sql 的 PL/SQL 触发器的主要内容,如果未能解决你的问题,请参考以下文章

oracle(sql)基础篇系列——PLSQL游标存储过程触发器

pl/sql基础练习

引发异常后 PL/SQL 继续

Oracle笔记4-pl/sql-分支/循环/游标/异常/存储/调用/触发器

PL/SQL 触发器不会运行

PL/SQL 触发器以防止插入