代码之家  ›  专栏  ›  技术社区  ›  Gaurav Soni

如何在不执行整个查询的情况下查找动态查询中使用的列

  •  1
  • Gaurav Soni  · 技术社区  · 6 年前

    问题陈述

    我有一个动态SQL,需要存储在表中,但在 存储sql我需要用列列表验证sql 存储在另一个表中。 如果不执行查询,是否可以在select中找到列的名称?

    方法1 我能想到的唯一选择是,尝试使用查询的解释计划并读取数据字典表中的元数据。但不幸的是,我无法找到任何包含此类数据的表。如果你知道这样的观点,请告诉我?

    方法2 使用DBMS_SQL。descripe\u COLUMNS包来查找列名,但我相信这将执行整个查询。

    2 回复  |  直到 6 年前
        1
  •  3
  •   Alex Poole    6 年前

    你不需要执行查询来获得列名,你只需要解析它;e、 g.举个简单的例子:

    set serveroutput on
    
    declare
      l_statement varchar2(4000) := 'select * from employees';
      l_c pls_integer;
      l_col_cnt pls_integer;
      l_desc_t dbms_sql.desc_tab;
    begin
      l_c := dbms_sql.open_cursor;
      dbms_sql.parse(c=>l_c, statement=>l_statement, language_flag=>dbms_sql.native);
      dbms_sql.describe_columns(c=>l_c, col_cnt=>l_col_cnt, desc_t=>l_desc_t);
    
      for i in 1..l_col_cnt loop
        dbms_output.put_line(l_desc_t(i).col_name);
      end loop;
    
      dbms_sql.close_cursor(l_c);
    exception
      when others then
        if (dbms_sql.is_open(l_c)) then
          dbms_sql.close_cursor(l_c);
        end if;
        raise;
    end;
    /
    

    哪些输出:

    EMPLOYEE_ID
    FIRST_NAME
    LAST_NAME
    EMAIL
    PHONE_NUMBER
    HIRE_DATE
    JOB_ID
    SALARY
    COMMISSION_PCT
    MANAGER_ID
    DEPARTMENT_ID
    
    PL/SQL procedure successfully completed.
    

    您可以对循环内的列名执行任何需要的验证。

    请记住,您只能看到(并验证)列表达式的列名或别名,这不一定反映实际检索的数据。有人可以创建一个查询,从其有权限访问的任何地方提取任何数据,然后给出被认为有效的列/表达式别名。

    如果您试图限制对特定数据的访问,请查看其他机制,如视图、虚拟私有数据库等。

        2
  •  2
  •   Jon Heller    6 年前

    DBMS\U SQL。PARSE不会执行SELECT语句,但它 执行DDL语句。如果字符串 'select * from employees' 替换为 'drop table employees' 代码将失败,但表仍将被删除。

    如果您只担心检索元数据的性能,那么Alex Poole的答案会很好。

    如果您担心运行错误的语句类型,那么您需要对Alex Poole的答案进行一些调整。

    令人惊讶的是,很难判断一个陈述是否是一个 SELECT 而不是其他东西。检查字符串开头的简单条件 select 将在99%的时间内工作,但从99%到100%是一个巨大的工作量。简单的正则表达式无法跟上所有不同的关键字、注释、替代引用格式、空格等。

    /*comment in front -- */ select * from dual
        select * from dual
    with asdf as (select * from dual) select * from asdf;
    ((((((select * from dual))))));
    

    如果你需要100%的准确性,我建议你使用我的开源软件 PLSQL_LEXER . 安装后,您可以可靠地测试以下命令类型:

    select
        statement_classifier.get_command_name('  /*comment*/ ((select * from dual))') test1,
        statement_classifier.get_command_name('alter table asdf move compress') test2
    from dual;
    
    TEST1    TEST2
    -----    -----
    SELECT   ALTER TABLE