【问题标题】:Oracle dynamic sql, find used tables in queryoracle动态sql,查询中查找使用过的表
【发布时间】:2019-10-22 14:59:30
【问题描述】:

有没有办法在 Oracle 动态 SQL 中找到已用表的列表。我需要设置一些表格的使用限制。

动态查询文本示例:

select *
  from Table1 T1
  join Table2 T2
    on T1.Col1 = T2.Col1
 where exists (select 1
          from Table3 T3
         where T1.Col2 = T3.Col2)

结果应该是:[Table1, Table2, Table3]。有什么想法吗?

【问题讨论】:

  • 我认为没有任何方法可以做到这一点。您也许可以解析解释计划调用的结果
  • 将查询放在一个字符串中,并使用正则表达式来查找 from 和 join 关键字之后的表?当您过滤掉TABLE ACCESS 所在的行时,解释输出的相同想法..
  • 感谢所有帮助解决此问题的人。我计划为我的软件添加机会,让用户可以通过自己编写 SQL Query 来获取报告。但问题是我不能允许使用所有表格和所有功能。我想,我应该找到另一种方法来解决这个问题

标签: oracle plsql dynamic-sql


【解决方案1】:

“有没有办法在 Oracle 动态 SQL 中找到已用表的列表”。

没有。也就是说,没有铸铁和直截了当的方法。动态 SQL 的后果之一是影响分析的难度增加。

确实,您也许能够在源代码中找到一些嵌入在文字字符串中的表名。

select *
from user_source
where lower(text) like '%table1%'
or  lower(text) like '%table2%'
or  lower(text) like '%table3%'

显然,您需要清除输出以隔离表名,并可能处理table17table23 上的误报。

但是,动态 SQL 通常会处理名称在运行时作为参数字符串传递或从数据字典中查询的表。你不太可能抓住所有这些。显然,这个差距的大小取决于你如何使用动态 SQL:也许你会没事的。

如果您的组织为 Tuning 和 Diagnostics 包付费,您可以使用 ASH 来查找已执行的 SQL ID,您可以对其进行解析以找到相关的表,幸运的话还可以预测生成和执行 SQL 的代码。

【讨论】:

    【解决方案2】:

    将您的动态 SQL 字符串放入 SQL SELECT 语句中,如下所示,以提取字符串中包含的表名:

    with t(str) as
    (
     select 'select *
      from Table1 T1
      join Table2 T2
        on T1.Col1 = T2.Col1
     where exists (select 1
              from Table3 T3
             where T1.Col2 = T3.Col2)' from dual
    ), t2 as
    (
      select level as row_num, regexp_substr(to_char(t.str),'^.*$',1,level,'m') as str
        from t
       connect by level <= length (to_char(t.str)) 
                         - length (replace (to_char(t.str), chr (10))) + 1 
    ), t3 as
    (
    select regexp_substr(
               regexp_substr(str,'From[[:space:]].*[[:space:]]',1,1,'i'),
                            '[^ ]+',1,2) as x,
           regexp_substr(
               regexp_substr(str,'Join[[:space:]].*[[:space:]]',1,1,'i'),
                            '[^ ]+',1,2) as y
      from t2 
    )
    select coalesce(x,y) as "Tables"
      from t3
     where coalesce(x,y) is not null;
    
    Tables
    -------
    Table1
    Table2
    Table3 
    

    Demo

    【讨论】:

      【解决方案3】:

      可以使用DBMS_UTILITY.EXPAND_SQL_TEXT、临时视图和查询DBA_DEPENDENCIES生成SQL语句使用的表列表。

      DBMS_UTILITY.EXPAND_SQL_TEXT 负责查找视图引用的表。临时视图和DBA_DEPENDENCIES 然后生成扩展 SQL 语句中使用的所有表的列表。

      功能

      create or replace function get_dependent_tables_from_sql(p_sql varchar2)
      return sys.odcivarchar2list authid current_user is
          v_expanded_sql clob;
          v_tables sys.odcivarchar2list := sys.odcivarchar2list();
          pragma autonomous_transaction;
      begin
          --Expand the SQL, which will go through all the recursive dependencies.
          dbms_utility.expand_sql_text
          (
              input_sql_text  => p_sql,
              output_sql_text => v_expanded_sql
          );
      
          --Create a view with the expanded SQL.
          execute immediate
          '
              create or replace view temp_view_for_dependencies as
              select count(*) the_count
              from
              (
              '||v_expanded_sql||'
              )
          ';
      
          --Find dependencies.
          --(Use execute immediate to simplify compilation privileges.)
          execute immediate
          q'[
              select distinct referenced_owner||'.'||referenced_name
              from dba_dependencies
              where name = 'TEMP_VIEW_FOR_DEPENDENCIES'
                  and owner = user
                  and referenced_type = 'TABLE'
          ]'
          bulk collect into v_tables;
      
          return v_tables;
      end get_dependent_tables_from_sql;
      /
      

      示例架构

      create table table1(col1 number, col2 number);
      create table table2(col1 number, col2 number);
      create table table3(col1 number, col2 number);
      create table table4(col1 number, col2 number);
      create table table5(col1 number, col2 number);
      create or replace view view1 as select 1 a from dual;
      

      调用函数

      select column_value table_name
      from table(get_dependent_tables_from_sql(q'[
              select *
              from table1 t1
              --ANSI joins
              join table2 t2
                  on t1.col1 = t2.col1
              where exists
              (
                  select 1
                  --Oracle style joins, views.
                  from table3 t3, table4, view1
                  where t1.col2 = t3.col2
              )
              --A table that won't be in execution plan.
              and exists (select 1 from table5 where 1 = 2)   
          ]'))
      order by 1;
      
      TABLE_NAME
      ----------
      JHELLER.TABLE1
      JHELLER.TABLE2
      JHELLER.TABLE3
      JHELLER.TABLE4
      JHELLER.TABLE5
      SYS.DUAL
      

      关于其他解决方案的警告

      小心涉及自定义 SQL 解析的解决方案。这是看起来非常容易的问题之一。您可以构建一个 98% 的时间都有效的正则表达式,但实际上不可能构建一个 100% 的时间有效的正则表达式。

      谨慎使用执行计划解决方案。将执行计划对象追溯到表并非易事,就像只使用索引一样。并且某些表可以在查询中使用,但由于连接消除而被排除在执行计划之外。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-09-17
        • 1970-01-01
        • 2021-03-21
        • 2020-08-21
        • 1970-01-01
        • 1970-01-01
        • 2014-04-08
        • 1970-01-01
        相关资源
        最近更新 更多