2016-12-21 89 views
0

我在一個程序上工作到克隆我的數據庫中的行從一個用戶到另一個用戶。它適用於我選擇行,編輯幾個值然後將其插回。在循環結果集時插入行

我還需要存儲新插入的行ID與他們現有的對應,以便我可以稍後克隆一些其他鏈接表。

我的代碼如下所示:

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會大聲吼我。

是否有插入行遍歷結果集沒有獲取整個結果集的方法嗎?

回答

1

Is there a way to insert rows while looping over a result set without fetching the entire result set?

是的。使用兩個MySQL連接:一個用於讀取,另一個用於寫入。

只要您沒有數千個程序實例試圖連接到同一個MySQL服務器,性能影響並不算太差。

一個連接正在讀取結果集,另一個連接將行插入到同一個表的末尾,因此不應該有死鎖。如果您用來讀取表的WHERE條件可以明確排除您要插入的行,如果有辦法將新行與舊行區分開來,這將會很有幫助。

在某種程度上,兩個連接的性能影響並不重要,因爲您沒有多少選擇。做你想做的唯一的另一種方式是將你的程序中的整個結果集寫入RAM中,關閉你的讀取光標,然後寫入。