1

我想要一个方法/代码片段来从 oracle 查询中提取列名和相应的表名。查询以及列名和表名在运行时会发生变化,并且通常会计算一些列名,这意味着它们被包装在函数中并具有别名。我尝试了不同的字符串标记技术,使用正则表达式根据 expeted 输出将其分离出来,但到目前为止,还没有运气!例如:

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;

我希望列的输出为:

任务名称
投资子团队名称
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

任何帮助公关指针将不胜感激。

4

3 回答 3

3

如果不编写自己的 SQL 编译器(至少是语义分析阶段的解析器和词法分析器),您实际上无法解决这个问题。这是一个非常重要的练习,特别是如果您想接受任何有效的 Oracle SQL 查询。Oracle Corporation 曾经为 SQL VM 和 PL/SQL VM 提供不同的 SQL 解析器,并且无法使它们保持同步——随着支持的 SQL 语法的改进,不断发展您的解析器是一项重大的时间和精力投资。

如果你真的决定走这条路,你可以从一些ANTLR SQL 语法开始。O'Reilly Flex 和 Bison 书中还有一章是关于解析 SQL 的,您可以将其用作起点。当然,您需要修改和扩展语法以支持您的查询可能包含的任何 SQL 功能。然后,您需要构建编译器的语法分析器和语义分析部分,以实现适当的范围解析规则,以便能够确定对特定列的特定引用来自哪个表。重申一下,这是一项重要的练习,并且必须针对数据库的每个新版本进行增强。

如果您可以放宽您的要求并对您将要看到的查询类型做出一些假设,那么编写解析器会变得容易得多。如果您可以保证每个查询都准确引用 1 个表,那么识别特定列来自哪个表会容易得多。如果您可以保证每个函数调用最多将一个表中的一列作为参数,那也会使事情变得更容易——否则,如果该列是将来自多个表的列作为参数的函数的结果。

于 2012-08-22T17:55:14.063 回答
1

我也同意这通常是不可能的。但也许解决方案是与 XML 消息的创建者取得联系,并就不同的协议达成一致,然后SELECT事先完成声明。同意他发送专栏。

如果这是不可能的,并且您想对查询的构建方式做出某些假设,那么您可以使用作为分隔符在 the 之后select和之前进行标记。但据我所知,您不能通过正则表达式子字符串命令真正做到这一点。我认为您需要编写一些 PL/SQL 函数。from,

但仍然要注意from关键字可能是选择列的一部分。如果你突然收到这样的查询,你会怎么做:

select 
  something, 
  (select count(*) from othertable) as cnt, 
  andfromthiscolumn xyz 
from mytable

所以我的建议是在组织上对其进行整理,然后尝试编写不可能的代码。

于 2012-08-22T18:54:10.617 回答
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;
于 2012-08-22T18:52:18.607 回答