2012-04-13 15 views
5

cx_Oracle pythonライブラリを使用してoracleで解析および実行したいSQLファイルがあります。 SQLファイルには、従来のDML/DDLとPL/SQLの両方が含まれています。Pythonでcx_Oracleを使用してPL/SQLとDML/DDLを使用してSQLファイルを解析します

create.sql

-- This is some ; malicious comment 
CREATE TABLE FOO(id numeric); 

BEGIN 
    INSERT INTO FOO VALUES(1); 
    INSERT INTO FOO VALUES(2); 
    INSERT INTO FOO VALUES(3); 
END; 
/
CREATE TABLE BAR(id numeric); 

私はのsqldeveloperまたはSQL * Plusでこのファイルを使用する場合、それは3つのクエリに分割して実行されます、それはこのように見ることができます。

しかし、cx_Oracle.connect(...)。cursor()。execute(...)では、ファイル全体ではなく、一度に1つのクエリしか取ることができません。両方のコメントが分割され(エラーが発生するため)、PL/SQLブロックが単一のコマンドとして実行されず、エラーが発生するため、string.split(';')(単にexecute a sql script file from cx_oracle?のように)を使用して文字列を分割することはできません。

私は、Oracleフォーラム(https://forums.oracle.com/forums/thread.jspa?threadID=841025)で、cx_Oracle自体がファイル全体を解析するようなものをサポートしていないことを発見しました。私の質問は - 私のためにこれを行うためのツールはありますか?例えば。私のファイルをクエリに分割するために呼び出すことができるPythonライブラリですか?

編集:最適なソリューションは、SQL * Plusを直接使用するようです。私はこのコードを使用しました:

# open the file 
f = open(file_path, 'r') 
data = f.read() 
f.close() 

# add EXIT at the end so that SQL*Plus ends (there is no --no-interactive :(
data = "%s\n\nEXIT" % data 

# write result to a temp file (required, SQL*Plus takes a file name argument) 
f = open('tmp.file', 'w') 
f.write(data) 
f.close() 

# execute SQL*Plus 
output = subprocess.check_output(['sqlplus', '%s/%[email protected]%s' % (db_user, db_password, db_address), '@', 'tmp.file']) 

# if an error was found in the result, raise an Exception 
if output.find('ERROR at line') != -1: 
    raise Exception('%s\n\nStack:%s' % ('ERROR found in SQLPlus result', output)) 
+0

同じ問題。基本的に、Oracleはbraindeadであり、実際には複数のSQL文を解析する組み込みの能力を持っていないので、SQL * PlusとSQL DeveloperとTOADはすべて*独自の*パーサを実装します:-( –

答えて

2

複数のステートメントを同時に実行することは可能ですが、半ハッキーです。ステートメントをラップして一度に1つずつ実行する必要があります。

これまで述べてきたように、これはセミコロンの問題を解決するものではありませんが、簡単な答えはありません。私はそれを見ると、3つのオプションがあります。

  1. 私は良いオプションとは思わない複雑なパーサーを書いてください。

  2. PythonからSQLスクリプトを実行しないでください。 Pythonコードに埋め込まれた別のPythonファイル、データベース内のプロシージャーなどに、簡単に構文解析できるように、別のSQLスクリプトにコードを入れてください。これはおそらく私の選択肢のほうです。

  3. subprocessを使用し、そのようにスクリプトを呼び出します。これは最も簡単で簡単なオプションですが、cx_Oracleはまったく使用しません。ここ

    >>> import subprocess 
    >>> cmdline = ['sqlplus','schema/[email protected]','@','tmp_test.sql'] 
    >>> subprocess.call(cmdline) 
    
    SQL*Plus: Release 9.2.0.1.0 - Production on Fri Apr 13 09:40:41 2012 
    
    Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved. 
    
    
    Connected to: 
    Oracle Database 11g Release 11.2.0.1.0 - 64bit Production 
    
    SQL> 
    SQL> CREATE TABLE FOO(id number); 
    
    Table created. 
    
    SQL> 
    SQL> BEGIN 
        2 INSERT INTO FOO VALUES(1); 
        3 INSERT INTO FOO VALUES(2); 
        4 INSERT INTO FOO VALUES(3); 
        5 END; 
        6/
    
    PL/SQL procedure successfully completed. 
    
    SQL> CREATE TABLE BAR(id number); 
    
    Table created. 
    
    SQL> 
    SQL> quit 
    Disconnected from Oracle Database 11g Release 11.2.0.1.0 - 64bit Production 
    0 
    >>> 
    
+0

こんにちは、 .callは妥当な解決策のようです(私はSQLファイルを制御できないので、2番目の選択肢は使用できません)。しかし、サブプロセスとしてsqlplusを実行すると、 "QUIT"コマンドを待つでしょう。非対話型(このように実行されるいくつかのSQLファイルがあります)。どのようにして標準入力を待たないように変更しますか? –

+0

@Savannah、SQLスクリプトに終了を追加できませんか? – Ben

+0

私は実行したスクリプトにdata = "%s \ n \ nEXIT"%dataのようなものを追加しました。 –

関連する問題