2016-08-09 11 views
2

私は現在、Pythonを使用して複数のSQLファイルを実行するスクリプトを作成しています。これはスクリプトを自動化するためのもので、Pythonは私のWindows 2008サーバー上にある唯一のツールです。私は1つのセットで動作するスクリプトを持っていますが、問題は他のセットが ';'で区切られたものではなく2つのステートメントを持つ場合です。ここに私のコードです:複数のステートメントを ";"で区切ってSQLファイルを実行します。 pyodbcを使用する

import os 
import pyodbc 

print ("Connecting via ODBC") 

conn = pyodbc.connect('DSN=dsn', autocommit=True) 

print ("Connected!\n") 

inputdir = 'C:\\path' 
cursor = conn.cursor() 

for script in os.listdir(inputdir): 

    with open(inputdir+'\\' + script,'r') as inserts: 

     sqlScript = inserts.readlines() 

     sql = (" ".join(sqlScript)) 

     cursor.execute(sql) 

     print (script) 

conn.close() 

print ('Run Complete!') 

このコードはファイル全体を表示するように機能しますが、 ";"の前に1つの文しか実行しません。

助けがあれば助かります。

ありがとうございました。

+1

多くのSQL APIは、単一の呼び出しで複数のステートメントを許可していません。別々の 'cursor.execute()'呼び出しでそれらを実行するだけではどうですか? – Barmar

答えて

4

pyodbcコネクタ(またはpymysql)のAPIは、SQL呼び出しで複数の文を使用できません。これはエンジン解析の問題です。 APIは、複数のステートメントを渡すために渡すSQLを完全に理解してから、複数の結果を返すように処理する必要があります。

以下のようなスクリプトへのわずかな変更は、あなたが別のコネクタを個別にあなたの文のそれぞれを送信できるようにする必要があり

import os 
import pyodbc 

print ("Connecting via ODBC") 

conn = pyodbc.connect('DSN=dsn', autocommit=True) 

print ("Connected!\n") 

inputdir = 'C:\\path' 

for script in os.listdir(inputdir): 
    with open(inputdir+'\\' + script,'r') as inserts: 
     sqlScript = inserts.readlines() 
     for statement in sqlScript.split(';'): 
      with conn.cursor() as cur: 
       cur.execute(statement) 
    print(script) 

conn.close() 

with conn.cursor() as cur:は、それぞれの後に適切に終了する、各文のカーソルを開閉通話が完了しました。

+0

この例をありがとう。私は最初のカーソル(カーソル= conn.cursor())は、スクリプトで使用されて表示されていないので不要ですかと思います。 – cndnflyr

+0

おっと、私はあなたが正しいと思います。私はそれを削除します。 – Mikuana

+0

この例でのマイナーな問題です。おそらく、 'readlines'が直接' split 'できない文字列のリストを返すので、 'inserts.readlines()'の代わりに 'inserts.read()'を実行するべきでしょう。 – MarSoft

2

より正確なアプローチは、コメントと引用符付きの文字列を解析することであり、その外にあるのは;だけです。そうしないと、ブロックコメント付きのいくつかのSQL文をコメントアウトした直後にコードが破損します。

私は自分自身で作成したステートマシンベースの実装です。このコードはおそらく醜いので、はるかに優れているので、気軽に改善してください。 MySQL形式の#開始コメントは扱えませんが、追加は簡単です。

def split_sql_expressions(text): 
    results = [] 
    current = '' 
    state = None 
    for c in text: 
     if state is None: # default state, outside of special entity 
      current += c 
      if c in '"\'': 
       # quoted string 
       state = c 
      elif c == '-': 
       # probably "--" comment 
       state = '-' 
      elif c == '/': 
       # probably '/*' comment 
       state = '/' 
      elif c == ';': 
       # remove it from the statement 
       current = current[:-1].strip() 
       # and save current stmt unless empty 
       if current: 
        results.append(current) 
       current = '' 
     elif state == '-': 
      if c != '-': 
       # not a comment 
       state = None 
       current += c 
       continue 
      # remove first minus 
      current = current[:-1] 
      # comment until end of line 
      state = '--' 
     elif state == '--': 
      if c == '\n': 
       # end of comment 
       # and we do include this newline 
       current += c 
       state = None 
      # else just ignore 
     elif state == '/': 
      if c != '*': 
       state = None 
       current += c 
       continue 
      # remove starting slash 
      current = current[:-1] 
      # multiline comment 
      state = '/*' 
     elif state == '/*': 
      if c == '*': 
       # probably end of comment 
       state = '/**' 
     elif state == '/**': 
      if c == '/': 
       state = None 
      else: 
       # not an end 
       state = '/*' 
     elif state[0] in '"\'': 
      current += c 
      if state.endswith('\\'): 
       # prev was backslash, don't check for ender 
       # just revert to regular state 
       state = state[0] 
       continue 
      elif c == '\\': 
       # don't check next char 
       state += '\\' 
       continue 
      elif c == state[0]: 
       # end of quoted string 
       state = None 
     else: 
      raise Exception('Illegal state %s' % state) 

    if current: 
     current = current.rstrip(';').strip() 
     if current: 
      results.append(current) 

return results 

そして、このようにそれを使用します。

with open('myfile.sql', 'r') as sqlfile: 
    for stmt in split_sql_expressions(sqlfile.read()): 
     cursor.execute(stmt) 
関連する問題