在遍历结果集时插入行

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 中,关闭阅读光标,然后写入。