2012-10-22 62 views
4

UPDATE
在根據Nathan的建議傳遞execute()行列表之後,代碼將在下面執行,但仍然執行得更多,但仍然卡住執行函數。錯誤消息爲:使用Python的SQL多重插入

query = query % db.literal(args) 
TypeError: not all arguments converted during string formatting 

所以它仍然無法正常工作。有人知道爲什麼現在有一個類型錯誤?
END UPDATE

我有一個很大的.xls格式的郵件列表。我使用python和xlrd將xls文件中的名稱和電子郵件檢索到兩個列表中。現在我想把每個名字和電子郵件放到一個mysql數據庫中。我爲這部分使用MySQLdb。很顯然,我不想爲每個列表項目執行插入語句。
這是我到目前爲止。

from xlrd import open_workbook, cellname 
import MySQLdb 

dbname = 'h4h' 
host = 'localhost' 
pwd = '[email protected]' 
user = 'root' 

book = open_workbook('h4hlist.xls') 
sheet = book.sheet_by_index(0) 
mailing_list = {} 
name_list = [] 
email_list = [] 

for row in range(sheet.nrows): 
    """name is in the 0th col. email is the 4th col.""" 
    name = sheet.cell(row, 0).value 
    email = sheet.cell(row, 4).value 
    if name and email: 
     mailing_list[name] = email 

for n, e in sorted(mailing_list.iteritems()): 
    name_list.append(n) 
    email_list.append(e) 

db = MySQLdb.connect(host=host, user=user, db=dbname, passwd=pwd) 
cursor = db.cursor() 
cursor.execute("""INSERT INTO mailing_list (name,email) VALUES (%s,%s)""", 
       (name_list, email_list)) 

遊標執行時的問題。這是錯誤:_mysql_exceptions.OperationalError: (1241, 'Operand should contain 1 column(s)')我試圖把我的查詢放入一個var最初,但它只是barfed關於傳遞一個元組執行()的消息。

我在做什麼錯?這甚至有可能嗎?

該列表是巨大的,我絕對不能把插入到一個循環。我看着使用LOAD DATA INFILE,但我真的不明白如何格式化文件或查詢,當我必須閱讀MySQL文檔時,我的眼睛流血。我知道我可能可能使用一些在線xls到mysql轉換器,但這對我來說也是一個學習練習。 有沒有更好的辦法

+0

請勿使用'%'運算符來構建查詢!密切關注Nathan的代碼。 – r3m0t

+1

@ r3m0t'query = query%db.literal(args)'是錯誤信息不是我的代碼。無論如何喬恩解決了我的問題。 – noel

回答

7

修復TypeError: not all arguments converted during string formatting - 您需要使用cursor.executemany(...)方法,因爲它接受可迭代的元組(多於一行),而cursor.execute(...)期望該參數爲單行值。

執行該命令之後,您需要確保該事務承諾使用db.commit()來使更改在數據庫中處於活動狀態。

+0

是不是這個道理! – noel

16

您需要給executemany()一個行列表。您不需要中斷名稱並將其發送到單獨的列表中,只需創建一個包含兩個值的列表即可。

rows = [] 

for row in range(sheet.nrows): 
    """name is in the 0th col. email is the 4th col.""" 
    name = sheet.cell(row, 0).value 
    email = sheet.cell(row, 4).value 
    rows.append((name, email)) 

db = MySQLdb.connect(host=host, user=user, db=dbname, passwd=pwd) 
cursor = db.cursor() 
cursor.executemany("""INSERT INTO mailing_list (name,email) VALUES (%s,%s)""", rows) 

更新:如@JonClements提到,它應該是executemany()不​​。

+0

謝謝修復了原來的問題,如果答案總是這麼快,我可能會開始變得懶惰。現在,我收到了一個類型錯誤,我確定這不是無法解決的問題。 – noel

+1

@shakabra嘗試使用'cursor.executemany(...)'代替 –

+0

@JonClements執行許多腳本組合,沒有錯誤,但我的數據庫仍然是空的。 – noel

1

如果您對代碼的高性能感興趣,這個答案可能會更好。

比較來excutemany方法,下面execute會快得多:

INSERT INTO mailing_list (name,email) VALUES ('Jim','[email protected]'),('Lucy','[email protected]') 

您可以輕鬆地修改從@Nathan Villaescusa答案,並獲得新的代碼。

cursor.execute("""INSERT INTO mailing_list (name,email) VALUES (%s)""".format(",".join(str(i) for i in rows)) 

這是我自己的測試結果:

excutemany:10000 runs takes 220 seconds 

execute:10000 runs takes 12 seconds. 

的速度差將是15倍左右。