我正在开发一个程序,用于将数据库中的行从一个用户克隆到另一个用户。我可以选择行,编辑一些值,然后将它们插入回来。
我还需要将新插入的 rowID 与现有的对应行一起存储,以便稍后可以克隆一些其他链接表。
我的代码如下所示:
import mysql.connector
from collections import namedtuple
con = mysql.connector.connect(host='127.0.0.1')
selector = con.cursor(prepared=True)
insertor = con.cursor(prepared=True)
user_map = {}
selector.execute('SELECT * FROM users WHERE companyID = ?', (56, ))
Row = namedtuple('users', selector.column_names)
for row in selector:
curr_row = Row._make(row)
new_row = curr_row._replace(userID=None, companyID=95)
insertor.execute('INSERT INTO users VALUES(?,?,?,?)', tuple(new_row))
user_map[curr_row.userID] = insertor.lastrowid
selector.close()
insertor.close()
运行此代码时,出现以下错误:
mysql.connector.errors.InternalError: Unread result found
我假设这是因为我正在尝试运行INSERT
,而我仍在循环SELECT
,但是我认为使用两个游标可以解决这个问题。为什么使用多个游标时仍然出现此错误?
我找到了使用 fetchall()
的解决方案,但我担心这会使用太多内存,因为 SELECT
可能会返回数千个结果。
import mysql.connector
from collections import namedtuple
con = mysql.connector.connect(host='127.0.0.1')
cursor = con.cursor(prepared=True)
user_map = {}
cursor.execute('SELECT * FROM users WHERE companyID = ?', (56, ))
Row = namedtuple('users', cursor.column_names)
for curr_row in map(Row._make, cursor.fetchall()):
new_row = curr_row._replace(userID=None, companyID=95)
cursor.execute('INSERT INTO users VALUES(?,?,?,?)', tuple(new_row))
user_map[curr_row.userID] = cursor.lastrowid
cursor.close()
这可行,但速度不是很快。我认为不使用fetchall()
会更快,但似乎如果我不获取完整的结果集,MySQL就会对我大喊大叫。
有没有办法在循环结果集时插入行而而不获取整个结果集?
最佳答案
Is there a way to insert rows while looping over a result set without fetching the entire result set?
是的。使用两个 MySQL 连接:一个用于读取,另一个用于写入。
只要您没有数千个程序实例尝试连接到同一台 MySQL 服务器,性能影响就不会太严重。
一个连接正在读取结果集,另一个连接正在将行插入到同一个表的末尾,因此不应出现死锁。如果您用来读取表的 WHERE 条件可以显式排除您正在插入的行,如果有办法区分新行和旧行,这将会很有帮助。
在某种程度上,两个连接对性能的影响并不重要,因为您没有太多选择。完成您想做的事情的唯一其他方法是将整个结果集放入程序中的 RAM 中,关闭读取光标,然后写入。
关于python - 在循环结果集时插入行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41267722/