【问题标题】:Executing SQL script into oracle db one statement at a time一次将SQL脚本执行到oracle db中
【发布时间】:2012-11-24 14:35:48
【问题描述】:

假设我有一个如下所示的 sql 脚本:

--split statement 1
ALTER TABLE abs
  ADD (make    VARCHAR2(2 byte),
     model    varCHAR2(12 BYTE),
     built_on DATE,
     serial    varchar2(123 BYTE));
    /

    --split statement 2 
     declare
     begin
         null;
     end;
     /

     --split statement 3
     insert into test (v,a,c)
     values ('1','jjoe;','232');

     --split statement 4
     create or replace function BLAH_BLAH(i_in varchar2)
     as
         l_one varchar2(12);
         l_two varchar2(12);
         l_three varchar2(12);
     begin
         l_one := 1;
         l_two := 3;

         insert into test (v,a,b)
         values ('1','jjoee;','232');


    exception when no_data_found then
        l_three := 3;


    end;
    /

基本上,脚本可以包含 DML、DCL、DDL 和匿名块。我希望能够拆分每个语句并单独执行它们,但当然是为了它们出现。

我想过使用正则表达式,我相信逻辑应该是这样的:

1) 如果字符串以 create|alter|drop|declare 开头,则获取从该字符串开头到分号的所有内容,然后是一个新行,然后是一个正斜杠(这里的关键是在匿名块的情况下,我们必须忽略 DML,直到我们到达终点)。

2) 如果字符串以 insert|delete|update|merge 开头(同样,如果我们已经在适用于要求 1 的块中,则忽略该字符串),获取从该字符串开头到分号的所有内容后跟一个没有正斜杠的换行符。

到目前为止,我已经在 Python 中提出了这个:

sql_commands = re.split('(?i)(((create|alter|drop|merge)+)(?m);(\s*)\n(\s*))|(;(\s*)\n(\s*)/)',sql_script)  

但是每次我尝试推进其他要求时,正则表达式开始不起作用(实际上输出有点时髦)并且变得复杂到让我迷失了。

我想在 Python 或 Java 中完成这项工作(我想,Java 实际上是首选,因为这是一个 oracle db)

如果 regex 不能真正完成这项任务,这不一定是正则表达式。我的最终目标是拆分每个语句并单独运行它,这样我就可以捕获出现的任何错误并优雅地处理它们。

【问题讨论】:

  • 所以您将一个脚本作为输入,其中有多个调用,并且您想将其拆分,并单独调用每个部分?
  • 完全正确。这里的目标是如果部分脚本失败,我要么想闪回更改,要么根据失败继续运行脚本。

标签: java python sql regex oracle


【解决方案1】:

根据您的目标,在每个语句的末尾插入以下命令后,您可以将文件提供给 SQL*Plus:

pause Press any key to proceed

【讨论】:

  • 嗯,这并没有解决寻找单个语句的问题,这是他试图解决的问题。
  • 非常正确的jschoen,我们已经使用了SQLPlus,但问题是sql即使有一部分失败了,plus也会继续执行整个脚本。
  • @Patrick 如果这是问题所在,请使用 WHENEVER SQLERROR EXIT SQL.SQLCODE
  • 如果您可以使用 sqlplus >=11,您甚至可以启用错误日志记录,请参阅tkyte.blogspot.it/2010/04/new-thing-about-sqlplus.html
  • @colemar 抱歉,但这不是我想要的。我不希望脚本在发生 sql 错误时退出,这取决于具体情况,这就是我要达到这些长度的原因,否则我会同意你的看法。例如:if "drop table abc;"失败是因为特定的错误是“无法删除表,因为表不存在”,我不希望整个脚本停止运行,表不存在也没关系,因为我无论如何都试图删除它。像“表空间不能扩展...”这样更严重的事情会停下来。
【解决方案2】:

伪代码,未经测试,只是为了展示想法:

while (line = readLine()) {
    String cmdString = null;
    if (line.beginsWith("create" || line.beginsWith("alter") ...) {
       String previousLine = line;
       while (line = readLine()) {
          if (line.equals("/") && previousLine.endsWith(";")) {
            executeSQL(cmdString);
            break;
          }
          previousLine = line;
          cmdString = cmdString + line;
       }
    }
    if (line.beginsWith("insert" || line.beginsWith("update") ...) {
       String previousLine = line;
       while (line = readLine()) {
          if (line.equals("\n") && previousLine.endsWith(";")) {
            executeSQL(cmdString);
            break;
          }
          previousLine = line;
          cmdString = cmdString + line;
       }
    }
    // skip others
}

【讨论】:

  • 看起来很有希望,我的脑袋被正则表达式缠住了,我没想到这么简单的循环可以处理这个问题。我会对此进行测试并回复您
  • 这是很棒的东西,我将它转换为 Python,它几乎可以按预期工作。需要去除空格和制表符。还需要加上“cmdString = cmdString + line;”在“String previousLine = line;”下方在进入第二个循环之前捕获记录的第一行。谢谢你。
  • 不客气。我更喜欢这样的解决方案。比您尝试过的 Regex 噩梦更具可读性和可维护性。我敢打赌,执行速度会更快。前几天我读到一个很好的编程技巧:总是像维护你的代码的人是一个知道你住在哪里的连环杀手一样编写代码。
猜你喜欢
  • 2020-03-22
  • 1970-01-01
  • 2020-12-04
  • 2020-11-17
  • 1970-01-01
  • 1970-01-01
  • 2020-07-14
  • 1970-01-01
相关资源
最近更新 更多