2016-08-09 7 views
2

나는 현재 Python을 사용하여 여러 SQL 파일을 실행하는 스크립트를 작성하고있다. 이것은 스크립트를 자동화하는 것이며 파이썬은 우리의 windows 2008 서버에있는 유일한 도구입니다. 하나의 세트에서 작동하는 스크립트가 있지만 문제는 다른 세트가 ';' 여기 내 코드는 다음과 같습니다.여러 개의 명령문을 ";"으로 분리하여 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

많은 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

예를 들어 주셔서 감사합니다. 첫 번째 커서 (cursor = conn.cursor())가 스크립트에서 사용 된 것을 볼 수 없기 때문에 불필요한 것인지 궁금합니다. – cndnflyr

+0

아, 네가 맞다고 생각해. 나는 그것을 제거 할 것이다. – Mikuana

+0

예제에서의 사소한 문제 - 아마도'inserts.readlines()'대신'inserts.read()'를해야합니다.'readlines'는 직접'split' 할 수없는 문자열 목록을 반환하기 때문입니다. – 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)