4

次のような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で実行したいと思います(これがOracle dbであることを考えると、実際にはJavaの方が好ましいと思います)

正規表現が実際にこのタスクに対応していない場合、これは正規表現である必要はありません。私の最終的な目標は、各ステートメントを分割して個別に実行し、発生したエラーを見つけて適切に処理できるようにすることです。

4

2 に答える 2

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
}
于 2012-12-06T15:13:43.737 に答える
-2

目的に応じて、各ステートメントの最後に次のコマンドを挿入した後、ファイルを SQL*Plus にフィードできます。

pause Press any key to proceed
于 2012-12-06T14:56:02.343 に答える