Dav*_*542 32 python mysql mysql-python
在 python 中运行类似以下内容的建议方法是什么:
self.cursor.execute('SET FOREIGN_KEY_CHECKS=0; DROP TABLE IF EXISTS %s; SET FOREIGN_KEY_CHECKS=1' % (table_name,))
Run Code Online (Sandbox Code Playgroud)
例如,这应该是三个单独的self.cursor.execute(...)语句吗?除了cursor.execute(...)做这样的事情之外,是否应该使用特定的方法,或者这样做的建议做法是什么?目前我的代码如下:
self.cursor.execute('SET FOREIGN_KEY_CHECKS=0;')
self.cursor.execute('DROP TABLE IF EXISTS %s;' % (table_name,))
self.cursor.execute('SET FOREIGN_KEY_CHECKS=1;')
self.cursor.execute('CREATE TABLE %s select * from mytable;' % (table_name,))
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,一切都是单独运行的……所以我不确定这是否是一个好主意(或者更确切地说 - 执行上述操作的最佳方法是什么)。也许BEGIN...END?
Dan*_*n M 12
我会创建一个存储过程:
DROP PROCEDURE IF EXISTS CopyTable;
DELIMITER $$
CREATE PROCEDURE CopyTable(IN _mytable VARCHAR(64), _table_name VARCHAR(64))
BEGIN
SET FOREIGN_KEY_CHECKS=0;
SET @stmt = CONCAT('DROP TABLE IF EXISTS ',_table_name);
PREPARE stmt1 FROM @stmt;
EXECUTE stmt1;
SET FOREIGN_KEY_CHECKS=1;
SET @stmt = CONCAT('CREATE TABLE ',_table_name,' as select * from ', _mytable);
PREPARE stmt1 FROM @stmt;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
END$$
DELIMITER ;
Run Code Online (Sandbox Code Playgroud)
然后运行:
args = ['mytable', 'table_name']
cursor.callproc('CopyTable', args)
Run Code Online (Sandbox Code Playgroud)
保持简单和模块化。当然,您应该进行某种错误检查,甚至可以让存储过程返回一个代码来指示成功或失败。
Inf*_*ity 11
在 的文档中MySQLCursor.execute(),他们建议使用multi=True参数:
operation = 'SELECT 1; INSERT INTO t1 VALUES (); SELECT 2'
for result in cursor.execute(operation, multi=True):
...
Run Code Online (Sandbox Code Playgroud)
您可以在模块的源代码中找到另一个示例。
我在项目中多次陷入此类问题。经过大量研究后,我发现了一些观点和建议。
execute()该方法一次可以很好地处理一个查询。因为在执行方法期间会照顾状态。我知道
cursor.execute(operation, params=None, multi=True)需要进行多次查询。但参数在这种情况下不能很好地工作,有时内部错误异常也会破坏所有结果。代码变得庞大且含糊不清。甚至文档也提到了这一点。
executemany(operation, seq_of_params)并不是每次都实施的好习惯。因为产生一个或多个结果集的操作构成未定义的行为,并且当实现检测到已通过操作的调用创建结果集时,允许(但不要求)引发异常。[来源-文档]建议1-:
制作一个查询列表,例如 -:
table_name = 'test'
quries = [
'SET FOREIGN_KEY_CHECKS=0;',
'DROP TABLE IF EXISTS {};'.format(table_name),
'SET FOREIGN_KEY_CHECKS=1;',
'CREATE TABLE {} select * from mytable;'.format(table_name),
]
for query in quries:
result = self.cursor.execute(query)
# Do operation with result
Run Code Online (Sandbox Code Playgroud)
建议2-:
用字典设置。
[you can also make this by executemany for recursive parameters for some special cases.]
quries = [
{'DROP TABLE IF EXISTS %(table_name);':{'table_name': 'student'}},
{'CREATE TABLE %(table_name) select * from mytable;':
{'table_name':'teacher'}},
{'SET FOREIGN_KEY_CHECKS=0;': ''}
]
for data in quries:
for query, parameter in data.iteritems():
if parameter == '':
result = self.cursor.execute(query)
# Do something with result
else:
result = self.cursor.execute(query, parameter)
# Do something with result
Run Code Online (Sandbox Code Playgroud)
您还可以将 split 与脚本一起使用。
Not recommended
with connection.cursor() as cursor:
for statement in script.split(';'):
if len(statement) > 0:
cursor.execute(statement + ';')
Run Code Online (Sandbox Code Playgroud)
注意-:我主要使用
list of query方法,但在一些复杂的地方使用 makedictionary方法。
我不会依赖multi=True该函数的任何参数execute,这非常依赖于驱动程序,也不会尝试尝试拆分字符上的字符串;,该字符可能嵌入在字符串文字中。最直接的方法是创建一个函数 ,execute_multiple它接受要执行的语句列表和一个rollback_on_error参数,以确定在任何语句导致异常时要执行的操作。
我使用 MySQLdb 和 PyMySQL 的经验是,默认情况下它们从 开始autocommit=0,换句话说,就好像您已经处于事务中并且需要显式提交。无论如何,这个假设适用于下面的代码。如果不是这种情况,那么您应该 1. 在连接后显式设置或 2. 修改此代码以在语句autocommit=0后面启动事务try
def execute_multiple(conn, statements, rollback_on_error=True):
"""
Execute multiple SQL statements and returns the cursor from the last executed statement.
:param conn: The connection to the database
:type conn: Database connection
:param statements: The statements to be executed
:type statements: A list of strings
:param: rollback_on_error: Flag to indicate action to be taken on an exception
:type rollback_on_error: bool
:returns cursor from the last statement executed
:rtype cursor
"""
try:
cursor = conn.cursor()
for statement in statements:
cursor.execute(statement)
if not rollback_on_error:
conn.commit() # commit on each statement
except Exception as e:
if rollback_on_error:
conn.rollback()
raise
else:
if rollback_on_error:
conn.commit() # then commit only after all statements have completed successfully
Run Code Online (Sandbox Code Playgroud)
您还可以拥有一个使用其参数列表处理准备好的语句的版本:
def execute_multiple_prepared(conn, statements_and_values, rollback_on_error=True):
"""
Execute multiple SQL statements and returns the cursor from the last executed statement.
:param conn: The connection to the database
:type conn: Database connection
:param statements_and_values: The statements and values to be executed
:type statements_and_values: A list of lists. Each sublist consists of a string, the SQL prepared statement with %s placeholders, and a list or tuple of its parameters
:param: rollback_on_error: Flag to indicate action to be taken on an exception
:type rollback_on_error: bool
:returns cursor from the last statement executed
:rtype cursor
"""
try:
cursor = conn.cursor()
for s_v in statements_and_values:
cursor.execute(s_v[0], s_v[1])
if not rollback_on_error:
conn.commit() # commit on each statement
except Exception as e:
if rollback_on_error:
conn.rollback()
raise
else:
if rollback_on_error:
conn.commit() # then commit only after all statements have completed successfully
return cursor # return the cursor in case there are results to be processed
Run Code Online (Sandbox Code Playgroud)
例如:
cursor = execute_multiple_prepared(conn, [('select * from test_table where count = %s', (2000,))], False)
Run Code Online (Sandbox Code Playgroud)
尽管不可否认,上述调用只有一个带参数的 SQL 准备语句。
情人眼里出西施,所以做某事的最佳方法是主观的,除非你明确告诉我们如何衡量。我可以看到三个假设选项:
multiMySQLCursor的选项(不理想)或者,您还可以更改查询以避免一些不必要的工作。
关于该multi选项,MySQL 文档对此非常清楚
如果 multi 设置为 True,execute() 能够执行操作字符串中指定的多个语句。它返回一个迭代器,可以处理每个语句的结果。但是,在这种情况下使用参数效果不佳,单独执行每个语句通常是一个好主意。
关于选项 2. 和 3.,这纯粹是您希望如何查看代码的偏好。回想一下,连接对象autocommit=FALSE默认具有连接对象,因此游标实际上cursor.execute(...)将调用批处理到单个事务中。换句话说,下面的两个版本是等效的。
self.cursor.execute('SET FOREIGN_KEY_CHECKS=0;')
self.cursor.execute('DROP TABLE IF EXISTS %s;' % (table_name,))
self.cursor.execute('SET FOREIGN_KEY_CHECKS=1;')
self.cursor.execute('CREATE TABLE %s select * from mytable;' % (table_name,))
Run Code Online (Sandbox Code Playgroud)
与
self.cursor.execute(
'SET FOREIGN_KEY_CHECKS=0;'
'DROP TABLE IF EXISTS %s;' % (table_name,)
'SET FOREIGN_KEY_CHECKS=1;'
'CREATE TABLE %s select * from mytable;' % (table_name,)
)
Run Code Online (Sandbox Code Playgroud)
Python 3.6 引入了超级优雅的 f 字符串,如果可以的话你应该使用它们。:)
self.cursor.execute('SET FOREIGN_KEY_CHECKS=0;')
self.cursor.execute('DROP TABLE IF EXISTS %s;' % (table_name,))
self.cursor.execute('SET FOREIGN_KEY_CHECKS=1;')
self.cursor.execute('CREATE TABLE %s select * from mytable;' % (table_name,))
Run Code Online (Sandbox Code Playgroud)
请注意,当您开始操作行时,这不再成立;在这种情况下,它变得特定于查询,您应该分析相关的内容。一个相关的问题是,一个大查询或许多小查询哪个更快?
最后,除非您有特定的理由不这样TRUNCATE做,否则使用它可能会更优雅。DROP TABLE
self.cursor.execute(
'SET FOREIGN_KEY_CHECKS=0;'
'DROP TABLE IF EXISTS %s;' % (table_name,)
'SET FOREIGN_KEY_CHECKS=1;'
'CREATE TABLE %s select * from mytable;' % (table_name,)
)
Run Code Online (Sandbox Code Playgroud)