python后端占位符与sql冲突产生报错解决方法
·
一、问题描述
在使用python编写后端时,占位符%s常常会与sql参数化查询中的%字符冲突导致错误,情况如下:
# 执行PeelForce查询
cursor.execute("""
SELECT [AdHocWIPDataRecordId]
,[WIPDataNameName]
,[WIPDataValue]
,[ObjectName]
FROM [ETL].[dbo].[Mes_WIPDataRecord]
where [ObjectName] like '%s%'
""", [mfg_order_name])
上述代码产生报错:
{
"success": false,
"message": "查询Lot信息时出错: not enough arguments for format string"
}
这个错误是 Python 格式化字符串参数不匹配 导致的,代码本意希望将参数mfg_order_name传递给%s占位符,但是字符串冲突的问题,导致SQL 查询字符串中的 '%s%' 被错误解析了。
这里有两个问题:
-
%s在 SQL LIKE 中表示匹配任意字符的 's' -
但 Python 的
cursor.execute()会把这个%s当作 参数占位符
# 你的代码
sql = "WHERE [ObjectName] like '%s%'"
params = [mfg_order_name]
# Python 尝试解析时:
# 发现字符串中有 %s(在 '%s%' 中)
# 但你已经提供了一个参数 [mfg_order_name]
# 所以它认为:字符串中有1个占位符,你提供了1个参数 → ✅ 数量匹配
# 但实际上,这个 %s 不是参数占位符,是 LIKE 模式的一部分!
# 占位符 %s 在字符串 '...' 内部
sql = "WHERE name LIKE '%s%'"
cursor.execute(sql, ['123'])
# Python 看到:字符串内有 %s,但它在引号里
# 这会被误解为:你想匹配包含字母 's' 的字符串
# 实际执行的可能是:WHERE name LIKE '%s%'(永远匹配不到)
为什么会出现这个错误?
因为 Django/PyODBC 会扫描整个 SQL 字符串查找 %s 占位符,当它找到 '%s%' 中的 %s 时,认为这是一个参数占位符,但:
-
这个
%s被单引号包围,应该是字符串字面量 -
但参数化查询的实现可能还是把它当作了占位符
-
导致实际参数数量计算错误
尝试更改代码
# 使用字符串拼接构建LIKE条件
like_pattern = f'%{mfg_order_name}%'
cursor.execute("""
SELECT [AdHocWIPDataRecordId]
,[WIPDataNameName]
,[WIPDataValue]
,[ObjectName]
FROM [ETL].[dbo].[Mes_WIPDataRecord]
where [ObjectName] like ?
""", [like_pattern])
# 执行PeelForce查询
cursor.execute("""
SELECT [AdHocWIPDataRecordId]
,[WIPDataNameName]
,[WIPDataValue]
,[ObjectName]
FROM [ETL].[dbo].[Mes_WIPDataRecord]
where [ObjectName] like '%%%s%%'
""", [mfg_order_name])
都没有解决。
二、解决方式
多次尝试后,更改代码为
# 使用字符串拼接构建LIKE条件
like_pattern = f'{mfg_order_name}%'
cursor.execute("""
SELECT [AdHocWIPDataRecordId]
,[WIPDataNameName]
,[WIPDataValue]
,[ObjectName]
FROM [ETL].[dbo].[Mes_WIPDataRecord]
where [ObjectName] like %s
""", [like_pattern])
问题解决。
三、思考
✅ 为什么这样修改能解决问题?
对比分析:
python
# ❌ 之前错误的写法 sql = "WHERE [ObjectName] like '%s%'" params = [mfg_order_name] # 问题:%s 在引号内,被视为字符串的一部分 # ✅ 现在正确的写法 sql = "WHERE [ObjectName] like %s" params = [like_pattern] # like_pattern = '123%' # 正确:%s 在 SQL 语法位置,参数中提供完整模式
执行过程:
text
你的代码:
SQL 发送给数据库:WHERE [ObjectName] like ?
参数单独发送:'123%'
数据库组合后:WHERE [ObjectName] like '123%'
之前的错误代码:
SQL 发送给数据库:WHERE [ObjectName] like '%s%'
参数单独发送:'123'
数据库组合后:WHERE [ObjectName] like '%s%'(参数被忽略)
📊 这种写法的优劣分析
✅ 优点:
1. 安全性高(防止SQL注入)
python
# 即使参数包含特殊字符也是安全的
like_pattern = f"'; DROP TABLE users; --%"
cursor.execute("WHERE name LIKE %s", [like_pattern])
# 安全:参数会被正确转义为普通字符串
# 不会执行 DROP TABLE 命令
2. 代码清晰
python
# 一目了然:占位符是 %s,参数是 like_pattern sql = "WHERE name LIKE %s" params = [like_pattern]
3. 类型安全
-
数据库知道参数是字符串类型
-
会自动进行类型转换和转义处理
⚠️ 缺点/注意事项:
1. 通配符处理需要手动
python
# 需要手动构建模式
like_pattern = f"%{search_term}%" # 包含
like_pattern = f"{search_term}%" # 开头
like_pattern = f"%{search_term}" # 结尾
like_pattern = f"_{search_term}%" # 第二个字符开始
2. 特殊字符转义
python
# 如果要搜索包含 % 或 _ 的文字
search_term = "100%" # 包含百分号
# 需要转义
like_pattern = f"%{search_term.replace('%', '\\%').replace('_', '\\_')}%"
3. 性能考虑(通配符位置)
python
# ✅ 好的性能:以固定前缀开头 like_pattern = "ABC%" # 可以使用索引 # ⚠️ 差的性能:以通配符开头 like_pattern = "%XYZ" # 无法使用索引,全表扫描 # ❌ 很差的性能:两边都有通配符 like_pattern = "%MNO%" # 全表扫描
更多推荐

所有评论(0)