Python:如何在包含原生花括号的SQL字符串中插入变量
核心报错原因
Python的str.format()在解析字符串时,会将所有单个出现的{、}识别为格式化占位符的边界标记。你写在SQL语句里用来匹配原生字符的单花括号,没有配套的占位符命名,会被解析器判定为格式异常,最终抛出Single '}' encountered in the format string.错误。你之前参考的“转义花括号”规则本身是正确的,只是没有对SQL里所有需要保留的字面花括号做对应处理。
解决方案
方法1:按照format规则转义字面花括号
str.format()的转义逻辑可拆解为三个规则:
- 连续两个
{{会被解析为输出一个字面{ - 连续两个
}}会被解析为输出一个字面} - 实际需要替换的变量占位符(比如
{v_User_ID})保持单花括号写法即可,不需要转义
按照这个规则修改后的可运行代码如下:
import psycopg2 import pandas as pd conn = psycopg2.connect(host="xxx", port = 5432, database="xxxx", user="xxx", password="xxxx") statment= """ Select User_name, replace(replace(product_name,'{{',''),'}}','') as product_name, date from Sales where user_id={v_User_ID} and shop_id={v_shop_id} UNION Select User_name, replace(replace(product_name,'{{',''),'}}','') as product_name, date from Sales where shop_id={v_shop_id} and country='France' """ test = statment.format(v_User_ID=181 ,v_shop_id=107) df= pd.read_sql_query(test ,con=conn) df.head()
注:上面代码同时修正了原SQL的隐含问题——PostgreSQL中字符串字面量需要用单引号包裹,原代码里写的country="France"用双引号会被识别为字段名,容易触发语法错误。
方法2:改用数据库驱动原生参数绑定(生产环境推荐)
直接用str.format()拼接SQL字符串,除了会和原生花括号产生解析冲突,还存在SQL注入风险。更稳妥的写法是跳过手动字符串拼接,借助pandas和psycopg2自带的参数传值能力,把需要替换的变量位置换成数据库驱动的占位符,完全绕开花括号解析的问题:
import psycopg2 import pandas as pd conn = psycopg2.connect(host="xxx", port = 5432, database="xxxx", user="xxx", password="xxxx") statment= """ Select User_name, replace(replace(product_name,'{',''),'}','') as product_name, date from Sales where user_id=%s and shop_id=%s UNION Select User_name, replace(replace(product_name,'{',''),'}','') as product_name, date from Sales where shop_id=%s and country='France' """ # 不需要手动拼接字符串,通过params参数传值,驱动会自动做类型适配和特殊字符转义 df = pd.read_sql_query(statment, con=conn, params=(181, 107, 107)) df.head()
这种写法下SQL里的花括号都是原生的单花括号,完全不经过str.format()解析,自然不会出现格式冲突。
内容的提问来源于stack exchange,提问作者Gross
相关产品推荐
相关产品推荐

