读取 .sql 文件以在 Python 中执行 (pymysql)

Jac*_*cob 5 python mysql pymysql

我正在尝试创建一个多脚本工具,它将采用 .sql 文件的参数并执行它。

我已经设置了一个简单的测试,仅在一个数据库上执行,但是语法每次都会给我带来问题。

DELIMITER $$
CREATE DEFINER=`a_user`@`%` PROCEDURE `a_procedure`(
    IN DirectEmployeeID TEXT,
    IN StartRange DATE,
    IN EndRange DATE
)
BEGIN
SELECT aColumn
WHERE thisThing = 1;
END$$
DELIMITER ;
Run Code Online (Sandbox Code Playgroud)

需要明确的是,该脚本已经过测试,并且在通过时可以正常工作,如下所示:

mysql -uuser -p -hhost -Pport databaseName < file.sql
Run Code Online (Sandbox Code Playgroud)

也可以通过 mysql 工作台工作。

我在另一个网站上看到了这种类型的解决方案:

with conn.cursor() as cursor:
    f = sys.argv[1]
    file = open(f, 'r')
    sql = " ".join(file.readlines())
    cursor.execute(sql)
Run Code Online (Sandbox Code Playgroud)

这给了我一个 MySQL 语法错误:

pymysql.err.ProgrammingError: (1064, u"You have an error in your SQL syntax; 
check the manual that corresponds to your MySQL server version for the right 
syntax to use near 'DELIMITER $$\n CREATE DEFINER=`a_user`@`%` PROCEDURE 
`MyCommissionsDirect`(\n \tIN ' at line 1")
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,脚本中存在 mysql 不喜欢的换行符。

然后我尝试了这个:

with conn.cursor() as cursor:
    f = sys.argv[1]
    file = open(f, 'r')
    sql = ''
    line = file.readline()
    while line:
        sql += ' ' + line.strip('\n').strip('\t')
        line = file.readline()
    print sql
    cursor.execute(sql)
Run Code Online (Sandbox Code Playgroud)

并出现另一个语法问题,打印显示这都是一行,这在 mysqlworkbench 中不起作用。甚至没有尝试执行它,这很奇怪。

当我首先将 DELIMETER $$ 放在单独的行上时,它会在 mysqlworkbench 中执行。

这是我觉得我可能会让事情变得越来越复杂的情况之一。我很惊讶 pymysql 没有直接执行 sql 文件的方法。我厌倦了尝试进行字符串操作并使其适用于这个特定的文件,因为那样的话,使这个工具变得模糊且可重用的梦想就破灭了。

我是否以完全错误的方式处理这个问题?

谢谢!

Rob*_*don 2

DELIMITER是 MySQL 解释器使用的命令,例如命令行或 Workbench,而不是实际的 MySQL 命令。

我最终在 Python 应用程序中使用了一些逻辑,以在DELIMITER定义时禁用 MySQL 查询的执行,然后在DELIMITER再次定义时执行:

import MySQLdb
import re

file = 'somesql.sql'
conn = MySQLdb.Connection(mysqlserver, mysqluser, mysqlpass, mysqldb)
curs = conn.cursor()
ignorestatement = False # by default each time we get a ';' that's our cue to execute.
statement = ""
for line in open(file):
    if line.startswith('DELIMITER'):
        if not ignorestatement:
            ignorestatement = True # disable executing when we get a ';'
            continue
        else:
            ignorestatement = False # re-enable execution of sql queries on ';'
            line = " ;" # Rewrite the DELIMITER command to allow the block of sql to execute
    if re.match(r'--', line):  # ignore sql comment lines
        continue
    if not re.search(r'[^-;]+;', line) or ignorestatement:  # keep appending lines that don't end in ';' or DELIMITER has been called
        statement = statement + line
    else:  # when you get a line ending in ';' then exec statement and reset for next statement providing the DELIMITER hasn't been set
        statement = statement + line
        # print "\n\n[DEBUG] Executing SQL statement:\n%s" % (statement)
        try:
            curs.execute(statement)
            conn.commit()
            statement = ""
        except curs.Error, e:
            print(file + " - Error applying (" + str(e) + ")\nTerminating.")
            sys.exit(1)
Run Code Online (Sandbox Code Playgroud)

这有点hacky,但似乎工作得很好。

  • 这是非常hacky..但似乎这种手工解析器是解决这个问题的唯一方法?这个问题的所有答案都采用相同的形式 (2认同)