在遍历结果集时插入行
Inserting rows while looping over result set
我正在开发一个程序,将我数据库中的行从一个用户克隆行到另一个用户。它适用于我选择行,编辑一些值然后将它们插入回来。
我还需要将新插入的 rowID 与其现有的对应行一起存储,以便稍后可以克隆一些其他 link 表。
我的代码如下所示:
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()
这可行,但速度不是很快。我在想 not 使用 fetchall()
会更快,但似乎如果我不获取完整的结果集然后 MySQL 对我大喊大叫。
有没有办法在 循环结果集 的同时插入行 而无需 获取整个结果集?
Is there a way to insert rows while looping over a result set without fetching the entire result set?
是的。使用两个 MySQL 连接:一个用于读取,另一个用于写入。
只要您没有成千上万的程序实例尝试连接到同一个 MySQL 服务器,性能影响就不会太差。
一个连接正在读取结果集,另一个正在将行插入到同一个 table 的末尾,因此您不应该出现死锁。如果您用来读取 table 的 WHERE 条件可以明确排除您插入的行,如果有一种方法可以区分新行和旧行,那将会很有帮助。
在某种程度上,两个连接的性能影响并不重要,因为您没有太多选择。做你想做的事情的唯一其他方法是将整个结果集放入程序的 RAM 中,关闭阅读光标,然后写入。
我正在开发一个程序,将我数据库中的行从一个用户克隆行到另一个用户。它适用于我选择行,编辑一些值然后将它们插入回来。
我还需要将新插入的 rowID 与其现有的对应行一起存储,以便稍后可以克隆一些其他 link 表。
我的代码如下所示:
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()
这可行,但速度不是很快。我在想 not 使用 fetchall()
会更快,但似乎如果我不获取完整的结果集然后 MySQL 对我大喊大叫。
有没有办法在 循环结果集 的同时插入行 而无需 获取整个结果集?
Is there a way to insert rows while looping over a result set without fetching the entire result set?
是的。使用两个 MySQL 连接:一个用于读取,另一个用于写入。
只要您没有成千上万的程序实例尝试连接到同一个 MySQL 服务器,性能影响就不会太差。
一个连接正在读取结果集,另一个正在将行插入到同一个 table 的末尾,因此您不应该出现死锁。如果您用来读取 table 的 WHERE 条件可以明确排除您插入的行,如果有一种方法可以区分新行和旧行,那将会很有帮助。
在某种程度上,两个连接的性能影响并不重要,因为您没有太多选择。做你想做的事情的唯一其他方法是将整个结果集放入程序的 RAM 中,关闭阅读光标,然后写入。