带有动态 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 TRIGGER
但ora_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游标存储过程触发器