执行 SQL 文件,多个语句由“;”分隔使用 pyodbc
Execute SQL file with multiple statements separated by ";" using pyodbc
我目前正在使用 Python 为 运行 多个 SQL 文件编写脚本,在您提到其他方法之前先了解一下背景知识;这是为了使脚本自动化,Python 是我在 windows 2008 服务器上拥有的唯一工具。我有一个适用于一组的脚本,但问题是当另一组有两个语句而不是一个由“;”分隔的语句时这是我的代码:
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!')
所以这段代码可以显示整个文件,但它只执行“;”之前的一条语句。
任何帮助都会很棒!
谢谢。
pyodbc 连接器(或 pymysql)中的 API 不允许在 SQL 调用中使用多个语句。这是引擎解析的问题; API 需要完全理解它传递的 SQL 才能传递多个语句,然后在 return.
上处理多个结果
像下面这样对您的脚本稍作修改应该允许您使用单独的连接器单独发送每个语句:
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:
为每个语句打开和关闭游标,在每次调用完成后适当退出。
更正确的做法是解析注释和引用的字符串,只考虑它们之外的;
。否则,在您用块注释注释掉几个 SQL 语句后,您的代码将立即被破坏。
这是我为自己制作的基于状态机的实现 - 这段代码可能很难看,但可以写得更好,所以请随时通过编辑我的答案来改进它。
它不处理 MySQL 风格的 #
开头的评论,但很容易添加。
def split_sql_expressions(text):
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:
yield 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:
yield current
并像这样使用它:
with open('myfile.sql', 'r') as sqlfile:
for stmt in split_sql_expressions(sqlfile.read()):
cursor.execute(stmt)
我目前正在使用 Python 为 运行 多个 SQL 文件编写脚本,在您提到其他方法之前先了解一下背景知识;这是为了使脚本自动化,Python 是我在 windows 2008 服务器上拥有的唯一工具。我有一个适用于一组的脚本,但问题是当另一组有两个语句而不是一个由“;”分隔的语句时这是我的代码:
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!')
所以这段代码可以显示整个文件,但它只执行“;”之前的一条语句。
任何帮助都会很棒!
谢谢。
pyodbc 连接器(或 pymysql)中的 API 不允许在 SQL 调用中使用多个语句。这是引擎解析的问题; API 需要完全理解它传递的 SQL 才能传递多个语句,然后在 return.
上处理多个结果像下面这样对您的脚本稍作修改应该允许您使用单独的连接器单独发送每个语句:
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:
为每个语句打开和关闭游标,在每次调用完成后适当退出。
更正确的做法是解析注释和引用的字符串,只考虑它们之外的;
。否则,在您用块注释注释掉几个 SQL 语句后,您的代码将立即被破坏。
这是我为自己制作的基于状态机的实现 - 这段代码可能很难看,但可以写得更好,所以请随时通过编辑我的答案来改进它。
它不处理 MySQL 风格的 #
开头的评论,但很容易添加。
def split_sql_expressions(text):
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:
yield 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:
yield current
并像这样使用它:
with open('myfile.sql', 'r') as sqlfile:
for stmt in split_sql_expressions(sqlfile.read()):
cursor.execute(stmt)