我想要一个方法/代码段从oracle查询中提取列名和相应的表名。查询以及因此列和表名称在运行时更改,并且通常计算一些列名称,这意味着它们包含在函数和别名中。我尝试了使用regexp的不同字符串标记技术,根据经过的输出将其分开,但到目前为止,没有运气! 例如:
select mandate_name, investment_sub_team_name,
fn_sum(REG_INV_CMP_AUM) REG_INV_CMP_AUM,
fn_sum(NON_REG_INV_CMP_AUM) NON_REG_INV_CMP_AUM
from DM_SAI_VALUATIONS_STEP3
where position_interval_type = 'E'
and position_type = 'T'
group by mandate_name, investment_sub_team_name;
我希望列的输出为:
mandate_name investment_sub_team_name fn_sum(REG_INV_CMP_AUM) fn_sum(NON_REG_INV_CMP_AUM)
上面注意:我希望列具有函数而不是别名
我希望表名的输出为:DM_SAI_VALUATIONS_STEP3,针对我上面列出的所有列
我无法编辑查询,因为它们是xml输出的一部分。所以,我无法改变别名。第二点是从查询中提取表名。请考虑这样一个事实:没有任何东西可以像字符串标记的位置那样硬编码,因为包含列和表的查询会有所不同。我正在寻找一种通用的方法来标记它们。所以,对于我期望的列输出,我只需要表名。它总是只去一个from子句中的一个表,所以提取它不会是一个问题。
预期产出:
Column Name Table Name
----------- ----------
mandate_name DM_SAI_VALUATIONS_STEP3
investment_sub_team_name DM_SAI_VALUATIONS_STEP3
fn_sum(REG_INV_CMP_AUM) DM_SAI_VALUATIONS_STEP3
fn_sum(NON_REG_INV_CMP_AUM) DM_SAI_VALUATIONS_STEP3
非常感谢任何帮助指针。
答案 0 :(得分:3)
如果没有编写自己的SQL编译器(至少解析器和词法分析器通过语义分析阶段),你实际上无法解决这个问题。这是一项非常重要的练习,特别是如果您想接受任何有效的Oracle SQL查询。 Oracle公司过去常常为SQL VM和PL / SQL VM提供不同的SQL解析器,并且无法使它们保持同步 - 随着支持的SQL语法的改进,这是时间和精力的一项重要投入,以保持解析器的发展。
如果您真的决心沿着这条路走下去,可以先从ANTLR SQL grammars开始。 O'Reilly Flex and Bison book还有一章解析SQL,你可以将其作为起点。当然,您需要修改和扩展语法,以支持查询可能包含的任何SQL功能。然后,您需要构建编译器的语法分析器和语义分析部分,以实现适当的范围解析规则,以便能够确定对特定列的特定引用来自哪个表。重申一下,这是一项非常重要的工作,必须针对数据库的每个新版本进行增强。
如果您可以放松您的要求并对您将要看到的各种查询做出一些假设,那么编写解析器会变得更加容易。如果您可以保证每个查询都完全引用1个表,那么识别特定列的哪个表就更容易了。如果您可以保证每个函数调用最多只能从一个表中的一列作为参数,那么这也会使事情变得更容易 - 否则,如果列是该列,您将需要确定要为表名返回的内容一个函数的结果,它从多个表中作为参数列。
答案 1 :(得分:0)
如果您知道查询字符串的结构不会发生太大变化,您可以执行以下操作:
set serveroutput on
set termout on
clear
declare
v_str varchar2(500) := 'select mandate_name, investment_sub_team_name,
fn_sum(REG_INV_CMP_AUM) REG_INV_CMP_AUM,
fn_sum(NON_REG_INV_CMP_AUM) NON_REG_INV_CMP_AUM
from DM_SAI_VALUATIONS_STEP3
where position_interval_type = ''E''
and position_type = ''T''
group by mandate_name, investment_sub_team_name;';
v_tmp varchar2(500);
v_cols varchar2(500);
v_table varchar2(500);
begin
v_tmp := replace( v_str, 'select ','');
v_tmp := substr( v_tmp, 1, instr(v_tmp, 'where')-1);
dbms_output.put_line('original query: '||v_str);
v_cols := substr (v_tmp, 1, instr(v_tmp, 'from')-1);
dbms_output.put_line('column names: '||v_cols);
v_table := substr(v_tmp, instr(v_tmp, 'from ')+4, 500);
dbms_output.put_line('table name: '||v_table);
end;
答案 2 :(得分:0)
我也同意这通常是不可能的。但也许解决方案是与XML消息的创建者取得联系,然后就不同的协议达成一致,然后事先完成SELECT
语句。同意他发送专栏。
如果这是不可能的,并且您想对如何构建查询做出某些假设,那么您可以使用select
作为分隔符在from
之后和,
之前进行标记化。但据我所知,你不能通过正则表达式子串命令真正做到这一点。我认为你需要编写一些PL / SQL函数。
但仍需谨慎from
关键字可能是列选择的某个部分。如果你突然得到这样的查询,你会怎么做:
select
something,
(select count(*) from othertable) as cnt,
andfromthiscolumn xyz
from mytable
所以我的建议是在组织上对其进行排序,然后尝试编写不可能的代码。