I'm trying to insert JSON data into an MySQL database:
def mapClients():
for d in devices:
clientMap = d['dot11.device']['dot11.device.associated_client_map'].keys()
for item in clientMap:
clientList = kr.device_by_mac(item)
times = kr.device_summary_since()
for c in clientList:
sqlMac = c['kismet.device.base.macaddr'],
sqlType = c['kismet.device.base.type'],
sqlManuf = c['kismet.device.base.manuf'],
ktime = c['kismet.device.base.last_time'],
for t in ktime:
sqlTime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(t))
cur.execute("INSERT INTO devices(apID,mac,type,manuf,last_seen) VALUES(1,'" + str(sqlMac) + "','" + str(sqlType) + "','" + str(sqlManuf) + "','" + sqlTime + "');")
conn.commit()
mapClients()
This returns the following error:
pymysql.err.ProgrammingError: (1064, u"You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'VALUES(1,'(u'58:E2:8F:CF:20:B3',)','(u'Wi-Fi Client',)','(u'Apple',)','20-10-201' at line 1")
I can see from the error that the various values are being suffixed with a 'u'. I understand through a lot of searching and learning that (I think) this means the data is unicode.
What I want to do is find a way of converting/decoding the data so the INSERT statements work. Some of the variables are tuples, some strings. Any help much appreciated.
2 Answers 2
You are inserting tuples, not strings; remove the trailing commas:
sqlMac = c['kismet.device.base.macaddr']
sqlType = c['kismet.device.base.type']
sqlManuf = c['kismet.device.base.manuf']
ktime = c['kismet.device.base.last_time']
sqlTime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(ktime))
It’s the trailing comma that turns those expressions into tuples, and str() on a tuple gives you the container Unicode string as the u'....' representation that then clashes with the ' quoting you are adding.
Note that removes the need to loop over ktime!
Next, you really want to use SQL parameters, not string concatenation. Use placeholders instead of '" + str(...) + "', and leave handling of quoting to the database adapter:
cur.execute("""
INSERT INTO devices (apID, mac, type, manuf, last_seen)
VALUES (1, %s, %s, %s, %s)
""", (sqlMac, sqlType, sqlManuf, sqlTime))
The %s are the placeholders; depending on your exact MySQL Python library, you may need to use ? questionmarks instead.
Not only would this let you avoid having to think about quoting, it also removes a serious security issue: the JSON you load could contain a SQL injection attack and SQL parameters are the best way to neutralise that attack vector.
6 Comments
%s placeholders, yes.ktime is an int now so you can just remove the for loop too and it should work. Remove the commas, I didn't notice the commas. @Martjin's rightFor the error message you posted, you have forgotten to place the closing parentheses before the VALUES in your SQL Query. The query should be like:
cur.execute("INSERT INTO devices(apID,mac,type,manuf,last_seen) VALUES(1,'" + str(sqlMac) + "','" + str(sqlType) + "','" + str(sqlManuf) + "','" + str(sqlTime) + "');")
(u'value')usevariable[0]. like replacestr(sqlMac)withstr(sqlMac[0])