psycopg2使用sql.Identifier、sql.Literal时报identifier函数不存在错误
错误根因
- 完全颠倒了psycopg2 sql模块的使用顺序,跳过了官方设计的转义逻辑:
你的代码是先对原生Python三引号字符串调用内置.format()方法,传入sql.Identifier('table_name')对象。原生字符串格式化会把sql.Identifier对象转换为其字符串表示(即纯文本Identifier('table_name'))直接嵌入SQL模板,之后才把这段嵌入了错误文本的字符串传给sql.SQL包装执行。 - 最终发送到数据库的SQL片段里,
select后的内容是Identifier('table_name'),PostgreSQL会把这段文本识别为对identifier函数的调用,由于不存在匹配的函数定义,就会抛出你遇到的psycopg2.errors.UndefinedFunction错误。 sql.Identifier、sql.Literal是psycopg2 sql模块的专属拼接元素,必须交给sql.SQL实例的内置方法处理,不能提前通过普通字符串格式化转成纯文本。
你之前去掉
sql.SQL和sql.Identifier直接传普通SQL字符串能正常运行,是因为不存在对象被转成错误文本的环节,数据库收到的是纯合法SQL文本。
正确实现方式
核心规则:
- 动态SQL模板先用
sql.SQL包裹,模板里的动态内容用{}做占位符 - 调用
sql.SQL实例自带的.format()方法,按占位符顺序传入对应的拼接元素:表名、字段名这类数据库标识符用sql.Identifier包裹,普通查询值用sql.Literal包裹 - 完成占位符替换的
sql.SQL实例再传给cur.execute()执行
代码示例
基础写法(替代你现在的代码)
query = sql.SQL(""" select {} from information_schema.tables where table_schema = 'my_schema'; """).format( sql.Identifier('table_name') ) cur.execute(query)
结合sql.Literal的写法(避免硬编码字符串)
query = sql.SQL(""" select {} from information_schema.tables where table_schema = {}; """).format( sql.Identifier('table_name'), sql.Literal('my_schema') ) cur.execute(query)
注意事项
- 不要对
sql.SQL实例使用Python原生的字符串格式化方式(f-string、%格式化、内置str.format()),必须走sql模块自带的替换逻辑,否则会失去自动转义、防SQL注入的作用。 - 不要把
sql.Identifier、sql.Literal对象和普通SQL文本直接做字符串拼接,会破坏转义规则。
内容的提问来源于stack exchange,提问作者NMALM。
相关产品推荐
相关产品推荐

