PyMySQL中cursor.execute传递字符串参数报错问题求助
问题原因分析
你遇到的这个问题,核心在于pymysql的参数化查询机制不能用来替换SQL中的标识符(比如表名、列名),它只适用于处理数据值(比如WHERE id = %s里的id值)。
当你用cursor.execute(sql, (table,))传递表名参数时,pymysql会把这个参数当作字符串值来处理,自动给它加上单引号,最终生成的SQL语句是:
SELECT * FROM 'table_1';
而MySQL里表名是不能用单引号包裹的(正确的做法是用反引号`包裹,或者如果表名是合法标识符的话可以不加),所以数据库会抛出语法错误,报错里的''table_1''其实是日志里对单引号的转义显示,实际就是'table_1'。
解决办法
要动态指定表名,你需要先严格校验表名的合法性(这一步非常关键,防止SQL注入攻击),然后用字符串拼接的方式生成SQL语句。
步骤1:校验表名
比如先定义一个允许访问的表名列表,只有在列表内的表名才允许查询:
ALLOWED_TABLES = {'table_1', 'table_2', 'user_info'} # 替换成你实际的表名
步骤2:修改函数逻辑
在执行SQL前先校验表名,然后用字符串格式化拼接表名(用反引号包裹,避免表名包含特殊字符时出错):
import pymysql import json connection = pymysql.connect( host='localhost', user='u_u_u_u_u', password='passwd', db='test', charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor ) ALLOWED_TABLES = {'table_1'} # 允许查询的表名单 def get_data(table): try: # 先校验表名合法性 if table not in ALLOWED_TABLES: raise ValueError(f"Table {table} is not allowed to access") with connection.cursor() as cursor: # 用反引号包裹表名,处理特殊表名的情况 sql = f"SELECT * FROM `{table}`;" cursor.execute(sql) result = cursor.fetchall() return json.dumps([dict(ix) for ix in result]) except (TypeError, pymysql.err.ProgrammingError, ValueError) as error: print(error) finally: pass get_data('table_1') connection.close()
为什么不能用参数化处理表名?
参数化查询的设计初衷是为了防止SQL注入,同时自动处理数据值的类型转换(比如字符串加引号、日期格式化等)。但表名属于SQL的结构部分,不是数据值,所以驱动会把参数当作普通字符串值处理,加上引号后就破坏了SQL的语法结构。
永远不要直接拼接未校验的用户输入作为表名,否则会存在严重的SQL注入风险。必须通过白名单或者严格的正则校验来确保表名的合法性。
内容的提问来源于stack exchange,提问作者ChumiestBucket
相关产品推荐
相关产品推荐

