如何在不执行整个查询的情况下查找动态查询中使用的列
How to find the column used in the dynamic query without executing whole query
问题陈述
I have a dynamic SQL which i need to store in a table ,but before
storing the sql i need to validate the sql with the list of columns
stored in another table.
Without executing the query , is it possible to find name of columns in the select ?
方法 1
我唯一能想到的选择是,尝试使用查询的解释计划并读取数据字典 table 中的元数据。但不幸的是我找不到任何 table 这样的 [=23] =] 如果你知道这样的观点,请告诉我?
方法 2
使用 DBMS_SQL.DESCRIBE_COLUMNS 包查找列名,但我相信这将执行整个查询。
你不需要执行查询来获取列名,你只需要解析它;例如举个简单的例子:
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.
您可以对循环内的列名进行任何需要的验证。
请记住,您只会看到(并验证)列表达式的列名或别名,这不一定反映实际检索的数据。有人可以设计一个查询,从任何它有权访问的地方提取任何数据,然后给出被认为有效的 columns/expression 别名。
如果您试图限制对特定数据的访问,请研究其他机制,如视图、虚拟专用数据库等。
DBMS_SQL.PARSE 不会执行 SELECT 语句,但 会 执行 DDL 语句。如果字符串 'select * from employees'
被 'drop table employees'
替换,代码将失败,但 table 仍将被删除。
如果您只担心检索元数据的性能,那么 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
问题陈述
I have a dynamic SQL which i need to store in a table ,but before storing the sql i need to validate the sql with the list of columns stored in another table. Without executing the query , is it possible to find name of columns in the select ?
方法 1 我唯一能想到的选择是,尝试使用查询的解释计划并读取数据字典 table 中的元数据。但不幸的是我找不到任何 table 这样的 [=23] =] 如果你知道这样的观点,请告诉我?
方法 2 使用 DBMS_SQL.DESCRIBE_COLUMNS 包查找列名,但我相信这将执行整个查询。
你不需要执行查询来获取列名,你只需要解析它;例如举个简单的例子:
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.
您可以对循环内的列名进行任何需要的验证。
请记住,您只会看到(并验证)列表达式的列名或别名,这不一定反映实际检索的数据。有人可以设计一个查询,从任何它有权访问的地方提取任何数据,然后给出被认为有效的 columns/expression 别名。
如果您试图限制对特定数据的访问,请研究其他机制,如视图、虚拟专用数据库等。
DBMS_SQL.PARSE 不会执行 SELECT 语句,但 会 执行 DDL 语句。如果字符串 'select * from employees'
被 'drop table employees'
替换,代码将失败,但 table 仍将被删除。
如果您只担心检索元数据的性能,那么 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