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 文件的方法。我厌倦了尝试进行字符串操作并使其适用于这个特定的文件,因为那样的话,使这个工具变得模糊且可重用的梦想就破灭了。
我是否以完全错误的方式处理这个问题?
谢谢!
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,但似乎工作得很好。