2014-06-25 60 views
1

我試圖用MySQLdb將數據從JSON字符串插入到MySQL。列的總數是固定的。 JSON字符串中的每行數據並不總是具有每列的值。當使用MySQL-Python將JSON數據插入MySQL時出現TypeError

這裏是我的示例代碼:

vacant_building = 'http://data.cityofchicago.org/resource/7nii-7srd.json?%24where=date_service_request_was_received=%272014-06-02T00:00:00%27' 
obj = urllib2.urlopen(vacant_building) 
data = json.load(obj) 

def insert_mysql(columns, placeholders, data): 
    sql = "INSERT INTO vacant_buildings (%s) VALUES (%s)" % (columns, placeholders) 
    db = MySQLdb.connect(host="localhost", user="xxxx", passwd="xxxx", db="chicago_data") 
    cur = db.cursor() 
    cur.execute(sql, data) 

for row in data: 
    placeholders = ', '.join(['%s'] * len(row)) 
    columns = ', '.join(c[:64] for c in row.keys()) 
    row_data = ', '.join(str(value) for value in row.values()) 
    insert_mysql(columns, placeholders, row_data) 

我得到以下錯誤:

query = query % tuple([db.literal(item) for item in args]) 
TypeError: not all arguments converted during string formatting 

我敢肯定的錯誤與我插入值的方式去做。我試圖將其更改爲:

sql = "INSERT INTO vacant_buildings (%s) VALUES (%s) (%s)" % (columns, placeholders, data) 

但我得到了1064錯誤。這是因爲這些值沒有用引號括起來(')。

想法解決?

回答

1

爲了使用MySQLdb的cursor.execute方法參數化您的查詢,execute的第二個參數必須是一個值序列;在for循環,你所參加的價值連成一個字符串以下行:既然你產生了一些佔位你的價值等於len(row)

row_data = ', '.join(str(value) for value in row.values()) 

,你需要提供很多值cursor.execute 。如果你只給它一個字符串,它會把整個字符串放到第一個佔位符中,而其他的沒有任何參數。這會拋出一個TypeError - 在這種情況下,消息會讀取「沒有足夠的格式字符串參數」,但我會假設您在複製/粘貼時簡單混合,因爲相反的情況(提供的參數過多/太少佔位符)按照您的指示讀取,「並非在字符串格式化過程中轉換的所有參數。」


爲了通過MySQLdb的一個變量組列運行一個INSERT聲明,你可以做,就像你爲列和佔位符做,但我更喜歡使用映射類型與擴展格式語法由MySQLdb支持(例如,%(name)s而不是%s)以確保我已經正確構建了我的查詢並且沒有將這些值放入任何錯誤的順序。我也喜歡在我自己的代碼中儘可能使用advanced string formatting

你可以準備好你的投入是這樣的:

max_key_length = 64 
columns = ','.join(k[:max_key_length] for k in row.keys()) 
placeholders = ','.join('%({})s'.format(k[:max_key_length]) for k in row.keys()) 
row_data = [str(v) for v in row.values()] 

注意到字典推導的順序是guaranteed,只要你不改變的同時,字典。

一般來說,這應該適用於insert_mysql函數中的那種代碼。但是,查看您實際從該URL拉取的JSON數據,您應該意識到您可能遇到嵌套問題;例如:

>>> pprint.pprint(data[0]) 
{u'address_street_direction': u'W', 
u'address_street_name': u'61ST', 
u'address_street_number': u'424', 
u'address_street_suffix': u'ST', 
u'any_people_using_property_homeless_childen_gangs_': True, 
u'community_area': u'68', 
u'date_service_request_was_received': u'2014-06-02T00:00:00', 
u'if_the_building_is_open_where_is_the_entry_point_': u'FRONT', 
u'is_building_open_or_boarded_': u'Open', 
u'is_the_building_currently_vacant_or_occupied_': u'Vacant', 
u'is_the_building_vacant_due_to_fire_': False, 
u'latitude': u'41.78353874626324', 
u'location': {u'latitude': u'41.78353874626324', 
       u'longitude': u'-87.63573355602661', 
       u'needs_recoding': False}, 
u'location_of_building_on_the_lot_if_garage_change_type_code_to_bgd_': u'Front', 
u'longitude': u'-87.63573355602661', 
u'police_district': u'7', 
u'service_request_number': u'14-00827306', 
u'service_request_type': u'Vacant/Abandoned Building', 
u'ward': u'20', 
u'x_coordinate': u'1174508.30988836', 
u'y_coordinate': u'1864483.93566661', 
u'zip_code': u'60621'} 

u'location'列的字符串表示:

"{u'latitude': u'41.78353874626324', u'needs_recoding': False, u'longitude': u'-87.63573355602661'}" 

你可能不希望它放入一個數據庫領域,特別是考慮到有原子/緯度領域已經在JSON對象。