Python 使用多条语句执行SQL文件,语句之间用“分隔”&引用;使用pyodbc
我目前正在编写一个脚本,使用Python运行多个SQL文件,在您提到其他方法之前,我有一点背景知识;这是为了自动化脚本,Python是我在windows 2008服务器上唯一的工具。我有一个适用于一个集合的脚本,但问题是另一个集合有两个语句,而不是一个用“;”分隔的语句这是我的密码:Python 使用多条语句执行SQL文件,语句之间用“分隔”&引用;使用pyodbc,python,pyodbc,netezza,Python,Pyodbc,Netezza,我目前正在编写一个脚本,使用Python运行多个SQL文件,在您提到其他方法之前,我有一点背景知识;这是为了自动化脚本,Python是我在windows 2008服务器上唯一的工具。我有一个适用于一个集合的脚本,但问题是另一个集合有两个语句,而不是一个用“;”分隔的语句这是我的密码: import os import pyodbc print ("Connecting via ODBC") conn = pyodbc.connect('DSN=dsn', autocommit=True)
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,以便传递多个语句,然后在返回时处理多个结果 对脚本稍作修改(如下面所示)应允许您使用单独的连接器分别发送每个语句:
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()
> CON.CURSORE()作为CUR:< /Cord>打开每个语句的游标,在每个调用完成后适当退出。
< P>更正确的方法是解析注释和引用字符串,并且只考虑<代码>;<代码>在它们之外。否则,在用块注释注释掉几个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)
许多SQL API不允许在一次调用中使用多个语句。为什么不使用单独的
cursor.execute()
调用来执行它们呢?示例中的一个小问题-您可能应该执行inserts.read()
而不是inserts.readlines()
asreadlines
返回不能直接拆分的字符串列表。重要提示:如果您有,此示例将崩溃代码>在/**/代码>注释,如注释掉的语句。更稳定的方法是解析注释和字符串文本,并仅在这些实体之外用分号分割。我同意这是一个不完整的解决方案。同样,这又回到了需要能够完全解析代码以便智能地拆分代码的问题上。如果你需要解析注释过的代码,一定要看看其他答案。将脚本拆分成单个语句对我来说是个好办法。如果我试着逐行读取文件,它太容易出错。但是用分号拆分,然后通过db.session.execute(sql)
执行每一条语句是有效的。非常感谢,伙计。有时解决方案非常简单……一种避免分号(无论是在注释还是表达式中)出现问题的方法是在多个字符上拆分。例如,您可以用“/**/;”或TAB结束所有语句;是的,您必须修改现有脚本以遵循此约定,并确保在其他地方避免此模式,但对我来说,通常情况下,sql实际上是从其他sql输出的,因此遵循此约定非常简单。