Скажем, у меня есть следующий код:
with open('saved_response.json') as data_file:
#data_ordered = json.load(data_file, object_pairs_hook=OrderedDict)
response=json.load(data_file)
for user_data in response['itemList']:
field_names=""
field_values=[]
for i in user_data:
field_names+=","+i
field_values.append(user_data[i])
print(field_names[1:])
print(field_values)
with con.cursor() as c:
c.execute("INSERT into user(%s) values(%s);",(field_names[1:],field_values))
Я получаю следующую ошибку:
ProgrammingError: (1064, "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 ''id,parentId,username,creationTime,role,state,userProfile') values((562949953421' at line 1")
Есть ли способ распечатать SQL-запрос, отправляемый в MySQL для выполнения, чтобы мы могли разрешить синтаксические ошибки, подобные этому? Также будет оценено решение этой ошибки.
Как отмечено в комментариях, также объекты курсора PyMySQL имеют недокументированный атрибут _last_executed
, который содержит отправленный запрос.
Ваши синтаксические ошибки являются результатом попытки передать идентификаторы, в этом случае имена столбцов, используя placeholder (s). Из сообщения об ошибке вы можете видеть, что
'id,...,userProfile') values((...
было отправлено. Другими словами, столбцы были отправлены как один (строковый) литерал. К сожалению, нельзя использовать заполнители для передачи идентификаторов. Для этого случая требуется построение строки запроса. Вы должны использовать белый список столбцов, а затем создать свой запрос.
Предложение VALUES также проблематично из-за двойных скобок. Оказывается, PyMySQL знает, как кодировать последовательности, передаваемые как "скалярные" аргументы:
In [65]: with conn.cursor() as cur:
...: cur.execute('select %s in %s',
...: ('z', ['\');DROP TABLE students -- ', 'x', 'y']))
...: print(cur.fetchone())
...: print(cur._last_executed)
...:
(0,)
select 'z' in ('\');DROP TABLE students -- ','x','y')
Поэтому вместо того, чтобы вставить скобки в список квадратных скобок, просто поместите местозаполнитель, где должен быть список значений.
ALLOWED_COLUMNS = {'id', 'parentId', 'username', 'creationTime',
'role', 'state', 'userProfile'}
for user_data in response['itemList']:
field_names, field_values = zip(*user_data.items())
unknown = set(field_names) - ALLOWED_COLUMNS
if unknown:
raise RuntimeError(f"Unknown columns: {unknown}")
field_names = ','.join(field_names)
with con.cursor() as c:
# Note: field names have been whitelisted. Normally one should avoid
# string formatting SQL queries.
c.execute(f"INSERT INTO user ({field_names}) VALUES %s", (field_values,))
В заключение, если ваши столбцы действительно используют смешанный случай и были созданы как таковые, вам, возможно, придется процитировать их.
with open('saved_response.json') as data_file:
#data_ordered = json.load(data_file, object_pairs_hook=OrderedDict)
response=json.load(data_file)
for user_data in response['itemList']:
field_names=[]
field_values=[]
for i in user_data:
field_names.append(i)
field_values.append(user_data[i])
print(field_names)
print(field_values)
with con.cursor() as c:
c.execute("INSERT into user(%s) values(%s);",(','.join(field_names), ','.join(str(field) for field in field_values)))
Проблема заключалась в том, что вы передавали список в %s
. Вы должны разделить поле_значения запятыми.