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

Oracle 如何在不执行整个查询的情况下查找动态查询中使用的列,oracle,oracle11g,dynamic-sql,Oracle,Oracle11g,Dynamic Sql,问题陈述 我有一个需要存储在表中的动态SQL,但在 存储sql我需要用列列表验证sql 存储在另一个表中。 如果不执行查询,是否可以在select中找到列的名称 方法1 我能想到的唯一选择是,尝试使用查询的解释计划并读取数据字典表中的元数据。但不幸的是,我无法找到任何包含此类数据的表。如果您知道此类视图,请告诉我 方法2 使用DBMS\u SQL.descripe\u COLUMNS包查找列名,但我相信这将执行整个查询。您不需要执行查询来获取列名,只需要解析它;e、 g.作为一个简单的例子: s

问题陈述

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

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

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

您不需要执行查询来获取列名,只需要解析它;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.
您可以对循环中的列名执行所需的任何验证

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


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

您不需要执行查询来获取列名,只需解析它;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.
您可以对循环中的列名执行所需的任何验证

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


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

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%的准确性,我建议你使用我的开源软件。安装后,您可以可靠地测试以下命令类型:

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

DBMS_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%的准确性,我建议你使用我的开源软件。安装后,您可以可靠地测试以下命令类型:

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

我认为这个问题只与查询有关,但我忘记了
parse
无论如何都会执行DDL,这是一个很好的提醒!我认为这个问题只与查询有关,但我忘记了
parse
无论如何都会执行DDL,这是一个很好的提醒!