Python 使用多条语句执行SQL文件,语句之间用“分隔”&引用;使用pyodbc

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)

我目前正在编写一个脚本,使用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,以便传递多个语句,然后在返回时处理多个结果

对脚本稍作修改(如下面所示)应允许您使用单独的连接器分别发送每个语句:

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()
as
readlines
返回不能直接拆分的字符串列表。重要提示:如果您有
,此示例将崩溃
/**/注释,如注释掉的语句。更稳定的方法是解析注释和字符串文本,并仅在这些实体之外用分号分割。我同意这是一个不完整的解决方案。同样,这又回到了需要能够完全解析代码以便智能地拆分代码的问题上。如果你需要解析注释过的代码,一定要看看其他答案。将脚本拆分成单个语句对我来说是个好办法。如果我试着逐行读取文件,它太容易出错。但是用分号拆分,然后通过
db.session.execute(sql)
执行每一条语句是有效的。非常感谢,伙计。有时解决方案非常简单……一种避免分号(无论是在注释还是表达式中)出现问题的方法是在多个字符上拆分。例如,您可以用“/**/;”或TAB结束所有语句;是的,您必须修改现有脚本以遵循此约定,并确保在其他地方避免此模式,但对我来说,通常情况下,sql实际上是从其他sql输出的,因此遵循此约定非常简单。