在过程中动态添加的表上创建触发器

Posted

技术标签:

【中文标题】在过程中动态添加的表上创建触发器【英文标题】:creating a trigger on a dynamically added table inside a procedure 【发布时间】:2017-04-23 21:41:16 【问题描述】:

我正在从 java 创建动态表。我想要的是我想在每个添加的新表上创建一个触发器,它只会使用序列来填充每个表中常见的主键(serial_no)。如何实现这一点???

编辑: 我已经尝试过这段代码,但我收到一条消息“程序创建时出现编译错误”

create or replace procedure "TRIGGER_CALL" (trigger_name IN VARCHAR2, table_name IN VARCHAR2, sno IN NUMBER) as begin CREATE SEQUENCE abc MINVALUE 1 MAXVALUE 10000 INCREMENT BY 1 START WITH 141 CACHE 20 NOORDER NOCYCLE; CREATE OR REPLACE TRIGGER trigger_name before insert on table_name for each row begin select s_no.nextval into :new.sno from dual; end; end;

编辑2: 我的代码

CREATE OR REPLACE
PROCEDURE "TRIGGER_CALL" (p_table_name   IN VARCHAR2) 
AUTHID CURRENT_USER                          
AS 
  l_sql VARCHAR2(4000);
  l_dummy NUMBER;
  l_trigger_name VARCHAR2(30);
  l_seq_name VARCHAR2(30);
BEGIN

  --SELECT '1'
    --INTO l_dummy
    --FROM all_tables
  -- WHERE table_name = UPPER(p_table_name);

  l_trigger_name := p_table_name || '_trg'; 
  l_seq_name := p_table_name || 's_no';
EXECUTE IMMEDIATE 'CREATE SEQUENCE l_seq_name start with 1 increment by 1 ';
  l_sql :=
    'CREATE OR replace TRIGGER ' || l_trigger_name ||
    '  BEFORE INSERT ON ' || p_table_name ||
    '  FOR EACH ROW 
     BEGIN 
       SELECT l_seq_name.NEXTVAL 
       INTO   :new.sno 
       FROM   dual;
     END;';

  EXECUTE IMMEDIATE l_sql;
END; 
/

【问题讨论】:

您的 Oracle 版本是多少?这在 12c 中更容易。 @WilliamRobertson 我有 Oracle 10g 。有什么建议吗?? 你必须做很长的路,然后 - 为你创建的每个表动态定义一个序列和一个触发器。 @WilliamRobertson 你能检查我的代码吗? 【参考方案1】:

请检查以下代码:

CREATE SEQUENCE my_sequence;
/

CREATE OR REPLACE
PROCEDURE "TRIGGER_CALL" (p_table_name   IN VARCHAR2) 
AUTHID CURRENT_USER                          
AS 
  l_sql VARCHAR2(4000);
  l_dummy NUMBER;
  l_trigger_name VARCHAR2(30);
BEGIN
  -- Validate if a p_table_name is a valid object name
  -- If you have access you can also use DBMS_ASSERT.SQL_OBJECT_NAME procedure
  SELECT '1'
    INTO l_dummy
    FROM all_tables
   WHERE table_name = UPPER(p_table_name);

  l_trigger_name := p_table_name || '_trg'; 

  l_sql :=
    'CREATE OR replace TRIGGER ' || l_trigger_name ||
    '  BEFORE INSERT ON ' || p_table_name ||
    '  FOR EACH ROW 
     BEGIN 
       SELECT my_sequence.NEXTVAL 
       INTO   :new.sno 
       FROM   dual;
     END;';

  EXECUTE IMMEDIATE l_sql;
END; 
/

CREATE TABLE my_test(sno NUMBER);
/

BEGIN
  trigger_call('my_test');
END;
/

重要提示:

    使用 AUTHID CURRENT_USER 消除了“权限不足”的问题。参考见:Execute Immediate within a stored procedure keeps giving insufficient priviliges error

    因为动态 sql 只是连接输入参数,因此需要对其进行验证以防止 SQL 注入。另见DBMS_ASSERT。

    由于第 2 点。我使用表名来构建触发器名称。

【讨论】:

我收到此错误消息“oracle pls-00103 在期望以下之一时遇到符号创建” 要在动态 sql 中使用 l_seq_name,您必须将其与字符串连接,您不能像发布的那样使用它(检查我如何使用 l_trigger_name 变量)。除了代码运行正常。我没有收到 PLS-00103 错误。你怎么称呼这个过程? 我在 sql 命令行中运行命令“show error procedure trigger_call” 我已经使用 SQLDeveloper 创建了该过程,它运行良好(记住我之前的评论)。您必须提供更多详细信息,否则我无法猜测您的问题是什么。也许您可以显示包含过程创建和错误详细信息的完整 sql 命令行。 您的问题解决了吗?如果是这样,请发布您的答案或接受此答案以供进一步参考。

以上是关于在过程中动态添加的表上创建触发器的主要内容,如果未能解决你的问题,请参考以下文章

如何在 ASP.NET Core MVC 中添加分页,在 AJAX 调用中动态创建的表上

delphi 动态添加系统菜单

带有动态创建行的表的表单

向动态创建的表行添加按钮

如何将新列动态添加到 bigquery 中已存在的表..?

MySQL必知必会读书笔记-8(表的操纵,视图,存储过程,游标,触发器)