在循环结果集时插入行

时间:2016-12-21 16:39:13

标签: python mysql python-3.x mysql-connector-python

我正在开发一个程序来将克隆数据库中的行从一个用户转移到另一个用户。它可以选择行,编辑几个值然后再插入它们。

我还需要将新插入的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:找到未读结果

我假设这是因为我正在尝试运行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会对我大喊大叫。

在没有获取整个结果集的情况下循环结果集时,有没有办法插入行

1 个答案:

答案 0 :(得分:1)

  

有没有办法在循环结果集时插入行而不提取整个结果集?

是。使用两个MySQL连接:一个用于读取,另一个用于写入。

只要您没有尝试连接到同一MySQL服务器的数千个程序实例,性能影响就不会太差。

一个连接正在读取结果集,另一个连接是将行插入到同一个表的末尾,因此您不应该有死锁。如果用于读取表的WHERE条件可以明确地排除您要插入的行,如果有一种方法可以告诉新行与旧行分开,那将会很有帮助。

在某种程度上,两个连接的性能影响并不重要,因为您没有太多选择。执行您想要做的唯一其他方法是将整个结果集放入程序的RAM中,关闭读取光标,然后写入。