【问题标题】:Getting a Tablename from all_tables for a trigger从 all_tables 获取触发器的表名
【发布时间】:2012-02-08 04:20:40
【问题描述】:

我们有一个应用程序可以使用随机生成的名称创建一个表。我想在这个表上创建一个触发器。因为我不知道表的名称,所以我想从 all_table 视图中获取它。我怎样才能实现这样的目标?

    create or replace trigger t1      
after insert or update on (select table_name from all_tables where owner = 'CustomAPP' and table_name like 'STAGE_%')  
     -- for each row
    declare
      -- local variables here
    begin

    end t1;

上面的 SQL 显然会报错,因为 create 触发器后面的 select 子句而不是表名。请指教

【问题讨论】:

  • 哇,您的应用程序正在创建具有随机名称(非常糟糕)的表(错误),并且您希望此应用程序在其上创建触发器(哎呀)。你到底想完成什么,也许有更好的方法?
  • 好吧,它不是我的应用程序,所以它的好坏不取决于我。我的客户使用该应用程序,他们不愿意摆脱它,我对此无能为力,我也无法控制该应用程序。由于应用程序创建随机表然后尝试从中删除内容,因此由于表上没有统计信息,因此进程运行非常缓慢。我正在创建一个触发器,该触发器在从表中删除记录之前在填充表后运行分析。我是手动完成的,这是一个巨大的改进。我不确定更好的方法可能是什么

标签: plsql triggers oracle10g


【解决方案1】:

您需要使整个CREATE TRIGGER 动态化才能执行此操作。像这样的东西应该工作。您可能希望触发器名称取决于表的名称,假设您对ALL_TABLES 的查询可能会返回多行。而且您当然希望触发器做某事,而不是让身体空空如也。

SQL> create table stg_12345( col1 number );

Table created.

SQL> begin
  2    for x in (select *
  3                from user_tables
  4               where table_name like 'STG%')
  5    loop
  6      execute immediate
  7        'create or replace trigger trg_foo ' ||
  8        ' before insert on ' || x.table_name ||
  9        ' for each row ' ||
 10        'begin ' ||
 11        '  null; ' ||
 12        'end;';
 13    end loop;
 14  end;
 15  /

PL/SQL procedure successfully completed.

SQL> select count(*) from user_triggers where trigger_name = 'TRG_FOO';

  COUNT(*)
----------
         1

当然,动态创建表格的应用程序的想法让我感到害怕。如果您对此有任何控制权,我强烈建议您重新考虑架构。

【讨论】:

  • 我知道它也会让我做噩梦。可悲的是,我对应用程序没有任何控制权:(
【解决方案2】:

解决方案 1:

如果问题是“由于缺乏统计信息而导致性能不佳”,那么在系统或会话级别更改 OPTIMIZER_DYNAMIC_SAMPLING 参数可能会有所帮助。请参阅Performance Tuning Guide 以获得更全面的讨论,但我发现默认值 2(64 个块)是不够的,特别是对于保持优化器统计信息最新的大型数据集是不切实际的。

解决方案 2:

如果您真的想在创建表后自动创建触发器,则需要为架构创建 DDL 触发器。下面的 SQL 证明了这一点。

CREATE OR REPLACE TRIGGER MAKE_ME_A_TRIGGER
AFTER CREATE ON CUSTOM_APP_SCHEMA
AS
  l_trigger_sql varchar2(4000);
BEGIN  
  if l_ora_obj_dict_type = 'TABLE'
  then
    l_trigger_sql := 'create or replace trigger ' || ora_dict_obj_name
                     ' before insert on ' || ora_dict_obj_type||   
                     ' for each row ' ||  
                     'begin ' ||  
                     '  null; ' ||
                     'end;'
    execute immediate l_sql;
  end if;
END;
/

【讨论】:

    【解决方案3】:

    您可以使用EXECUTE IMMEDIATE 动态执行 SQL,包括 DDL 脚本,前提是活动连接对数据库具有适当的权限。使用PL/SQL通过字符串连接构建完整的DDL语句,然后就可以动态执行了。

    文档: http://docs.oracle.com/cd/B12037_01/appdev.101/b10807/13_elems017.htm

    更多文档: http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/dynamic.htm

    【讨论】:

    • 我将动态 sql 放在哪里。我试图将它放在触发器规范的 select 语句之前,但它失败并说触发器规范无效。如果没什么大不了的,你能发布一个代码 sn-p 吗?
    猜你喜欢
    • 1970-01-01
    • 2017-02-11
    • 2019-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-06
    • 1970-01-01
    • 2013-08-05
    相关资源
    最近更新 更多