相同PostgreSQL插入语句pgAdmin正常,psycopg2报未终止引号错误原因
问题根因
- 编码不匹配导致SQL截断:psycopg2连接未显式指定客户端编码,当数据库编码与Python客户端默认编码不一致时,不可见字符或特殊符号会让SQL字符串在解析时被提前截断,刚好在
'HPBB361C位置断开,导致PostgreSQL收到的请求缺少闭合引号。pgAdmin执行时编码匹配,因此不会触发截断。 - 动态构造SQL存在转义风险:直接拼接完整SQL字符串传入execute的写法,很容易因为特殊字符、转义规则差异触发异常,即使肉眼看语句完全一致,实际传输的内容可能已经发生变化。
- 你贴出的执行代码本身存在缩进错误,
cur.execute(sql)不在try块覆盖范围内,异常捕获逻辑会失效。
修复步骤
- 先校验实际执行的SQL内容:在
cur.execute(sql)前添加print(repr(sql)),对比输出的字符串和你预期的完整SQL是否一致,确认是否存在截断、多余转义字符或不可见字符。 - 修正代码缩进,补充事务处理逻辑:插入操作必须手动提交才能生效,出错时需要回滚事务避免后续连接异常:
def SQLExec(conn,sql): try: cur = conn.cursor() cur.execute(sql) conn.commit() cur.close() except (Exception, psycopg2.DatabaseError) as error: print("***** ERROR:",error) conn.rollback() if cur: cur.close()
- 显式指定连接编码:创建数据库连接时添加编码参数,强制客户端与数据库编码一致:
conn = psycopg2.connect( # 原有连接参数(host、port、user、password、dbname) options="-c client_encoding=utf8" )
- (推荐)改用psycopg2原生参数化查询写法,从根源避免引号、转义类问题:
def SQLExec(conn, sql_template, params): try: cur = conn.cursor() cur.execute(sql_template, params) conn.commit() cur.close() except (Exception, psycopg2.DatabaseError) as error: print("***** ERROR:",error) conn.rollback() if cur: cur.close() # 调用示例 insert_template = """ INSERT INTO lytnobjects.devices (id,idedge,uniqueref,constructeur,ipaddress,macaddress,hostname,devicetype,isfirewall,isvisible,iscorporate,ishub,osname,osversion,datecreation,lasttrafic,hourtrafic,daytrafic,monthtrafic) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) """ insert_params = ( 'e1e455e98b6ed0037a58d0c1f5dc245a',3183,'TODO','TODO','192.168.143.49', 'b0:0c:d1:bb:36:1c','HPBB361C','Other',False,False,False,False,'','', '2021-10-29T00:58:53.709','2021-01-01T00:00:00','0/0','0/0','0/0' ) SQLExec(conn, insert_template, insert_params)
内容的提问来源于stack exchange,提问作者Jmcambot
相关产品推荐
相关产品推荐

