如何使用“pymysql”打印发送到 mySQL 的查询?

Posted

技术标签:

【中文标题】如何使用“pymysql”打印发送到 mySQL 的查询?【英文标题】:How to print the query being sent to mySQL using 'pymysql'? 【发布时间】:2018-12-13 00:02:36 【问题描述】:

假设我有以下代码:

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")

有没有办法打印发送到 MySQL 执行的 SQL 查询,以便我们可以解决这样的语法错误? 此外,将不胜感激此错误的解决方案。

【问题讨论】:

你见过***.com/questions/7071166/…吗? 【参考方案1】:
try: 
    c.execute("INSERT into user(%s) values(%s);",(field_names[1:],field_values))
except:
    print(c._last_executed)
    raise

【讨论】:

【参考方案2】:
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。

【讨论】:

【参考方案3】:

正如 cmets 中所指出的,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,))

最后一点,如果您的列确实使用混合大小写并且是这样创建的,您可能必须引用它们。

【讨论】:

以上是关于如何使用“pymysql”打印发送到 mySQL 的查询?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 pymysql 将 mySQL 查询结果存储到 pandas DataFrame 中?

用 pymysql 打印 MySQL/MariaDB 的所有库名表名和字段名

如何解决 pymysql.err.ProgrammingError: 1064 - 在 mysql 上保存数据?

PyMySQL的使用详解

MySQL高级之PyMySQL的使用

如何使用pymysql连接MySQL数据库