Oracle sql终结者筛选(+奇怪的行为)

时间:2015-05-27 14:54:49

标签: sql regex oracle exception

我有一个查询,比如说这个

SELECT to_char(regexp_substr(q'{select * from dual minus select * from dual; select * from dual minus select * from dual;}'
, '[^;]+', 1, LEVEL)) FROM dual
CONNECT BY to_char(regexp_substr(q'{select * from dual minus select * from dual; select * from dual minus select * from dual;}', '[^;]+', 1, LEVEL)) IS NOT NULL;

它运行正常 - 分割我的行

  

从双减去select * from double中选择*;从双重中选择*   减去select * from dual;

分为两个

  

从双减去select * from double选择*    从双重中选择*   减去select * from dual

一切都很好,直到我添加一些线刹,就像这样

SELECT to_char(regexp_substr(q'{select * from dual minus select * from dual; 
select * from dual minus select * from dual;}'
, '[^;]+', 1, LEVEL)) FROM dual
CONNECT BY to_char(regexp_substr(q'{select * from dual minus select * from dual; 
select * from dual minus select * from dual;}', '[^;]+', 1, LEVEL)) IS NOT NULL;

这里变成了地狱:sql在字符串中处理;,就像查询的实际结束一样,ORA-01756和东西......

如果我在;之后添加一个随机符号,那么一切都会好起来的

SELECT to_char(regexp_substr(q'{select * from dual minus select * from dual;%
select * from dual minus select * from dual;}'
, '[^;]+', 1, LEVEL)) FROM dual
CONNECT BY to_char(regexp_substr(q'{select * from dual minus select * from dual;%
select * from dual minus select * from dual;}', '[^;]+', 1, LEVEL)) IS NOT NULL;

请解释此行为并建议解决方法。

UPD :在不同的IDE(SQL开发人员而不是PL / SQL开发人员)中尝试过此操作。没有错误。也许这就是编码...
UPD2 :在这种情况下,SQLPlus的工作方式与PL / SQL开发人员的工作方式相同。 SQL开发人员似乎有点“聪明”。不过,不知道为什么。

2 个答案:

答案 0 :(得分:1)

尝试:

SELECT to_char(regexp_substr(q'{select * from dual minus select * from dual;
select * from dual minus select * from dual;}'
, '[^;[:cntrl:]]+', 1, LEVEL)) FROM dual
CONNECT BY to_char(regexp_substr(q'{select * from dual minus select * from dual;
select * from dual minus select * from dual;}', '[^;[:cntrl:]]+', 1, LEVEL)) IS NOT NULL;

输出:

select * from dual minus select * from dual
select * from dual minus select * from dual

原因是regexp_substr查找您指定的下一个模式,在您的情况下最初是[^;] +,此模式将找到;而下一个字符将是换行符。如果你想分解这样的行,简单的解决方案是通过[:cntrl:]

排除正则表达式搜索中的控制字符

答案 1 :(得分:1)

我创建了开源项目plsql_lexer来解决这些问题。

对于复杂的SQL语句,拆分可能会变得棘手。在语句拆分后,您可能想知道如何处理它们,以及如何报告它们。 STATEMENT_CLASSIFIER.CLASSIFY和STATEMENT_FEEDBACK.GET_FEEDBACK_MESSAGE程序可以帮助完成该任务。

示例代码

以下是一些示例,从您的示例开始并添加一些其他案例。每个样本将字符串拆分为两个语句。

declare
    procedure print_split_strings(p_statements nclob) is
        v_split_statements nclob_table;
    begin
        v_split_statements := statement_splitter.split(p_statements);
        for i in 1 .. v_split_statements.count loop
            dbms_output.put_line('Statement '||i||': '||v_split_statements(i));
        end loop;
    end;
begin
    --This is a simple case.
    print_split_strings('select * from dual minus select * from dual; select * from dual minus select * from dual;');
    --Ignore semicolons in comments.
    print_split_strings('select * from dual a;/* a comment ; */ select * from dual b;');
    --Ignore semicolons in strings.
    print_split_strings(q'{select '''' || q'!'!' from dual a;select * from dual b;}');
    --Ignore semicolons in matching BEGIN/ENDs in PLSQL_DECLARATIONS:
    print_split_strings('with function f return number is begin return 1; end; function g return number is begin return 2; end; select f from dual;select 1 from dual;');
end;
/

Statement 1: select * from dual minus select * from dual;
Statement 2:  select * from dual minus select * from dual;
Statement 1: select * from dual a;
Statement 2: /* a comment ; */ select * from dual b;
Statement 1: select '''' || q'!'!' from dual a;
Statement 2: select * from dual b;
Statement 1: with function f return number is begin return 1; end; function g return number is begin return 2; end; select f from dual;
Statement 2: select 1 from dual;