Как напечатать запрос, отправляемый в mySQL, используя 'pymysql'? - PullRequest
0 голосов
/ 04 июля 2018

Допустим, у меня есть следующий код:

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 для выполнения, чтобы мы могли разрешить синтаксические ошибки, подобные этой? Также будет оценено решение этой ошибки.

Ответы [ 2 ]

0 голосов
/ 04 июля 2018

Как отмечено в комментариях, также объекты курсора PyMySQL имеют недокументированный атрибут _last_executed, который содержит отправленный запрос.

Ваши синтаксические ошибки являются результатом попытки передать идентификаторы, в данном случае имена столбцов, с использованием заполнителей. Из сообщения об ошибке видно, что

'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,))

В заключение: если ваши столбцы действительно используют смешанный регистр и были созданы как таковые, вам, возможно, придется их заключить в кавычки.

0 голосов
/ 04 июля 2018
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. Вы должны отделить field_values ​​запятыми.

...