执行含INSERT、查询、DROP的SQL时psycopg报错:无结果返回
问题:psycopg执行多语句SQL调用fetchall()报错"the last operation didn't produce a result"
我有一段包含INSERT(冲突时更新)、查询临时表、删除临时表的SQL,在DBWeaver客户端执行正常,但用Python的psycopg库执行后调用fetchall()时,抛出ProgrammingError,提示**"the last operation didn't produce a result"**。
对应SQL语句
insert into test(id,name) select * from tmp_tbl on conflict(id) do update set name = EXCLUDED.name; with selected_data as (select * from tmp_tbl) select * from selected_data; drop table if exists tmp_tbl;
对应Python代码
with psycopg.connect(self.connect_str, autocommit=True) as conn: with conn.cursor() as cur: cur.execute(sql_full) rows = cur.fetchall() colnames = [desc[0] for desc in cur.description] df_result = pd.DataFrame(rows, columns=colnames) return df_result
错误信息
File "/usr/local/lib/python3.12/site-packages/psycopg/cursor.py", line 223, in fetchall self._check_result_for_fetch() File "/usr/local/lib/python3.12/site-packages/psycopg/_cursor_base.py", line 588, in _check_result_for_fetch raise e.ProgrammingError("the last operation didn't produce a result") psycopg.ProgrammingError: the last operation didn't produce a result
原因
你执行的是多条SQL语句的组合,psycopg执行完整个语句块后,游标默认指向最后一条执行的语句——也就是drop table if exists tmp_tbl;。这条DDL操作不会返回结果集,所以调用fetchall()时就会触发报错。而DBWeaver这类客户端会自动遍历所有语句的结果集并展示,但psycopg的游标不会自动处理,只会跟踪当前指向的语句结果。
解决方法
方法1:拆分SQL语句,单独执行并获取查询结果
将三条SQL分开执行,仅对查询语句调用fetchall():
with psycopg.connect(self.connect_str, autocommit=True) as conn: with conn.cursor() as cur: # 执行INSERT冲突更新 cur.execute("insert into test(id,name) select * from tmp_tbl on conflict(id) do update set name = EXCLUDED.name;") # 执行查询并获取结果 cur.execute("with selected_data as (select * from tmp_tbl) select * from selected_data;") rows = cur.fetchall() colnames = [desc[0] for desc in cur.description] df_result = pd.DataFrame(rows, columns=colnames) # 执行临时表删除 cur.execute("drop table if exists tmp_tbl;") return df_result
方法2:使用nextset()切换结果集
如果必须一次性执行所有SQL,可通过nextset()跳过无结果的语句,定位到查询语句的结果集:
with psycopg.connect(self.connect_str, autocommit=True) as conn: with conn.cursor() as cur: cur.execute(sql_full) # 跳过INSERT语句的无结果集 cur.nextset() # 此时游标指向查询语句的结果,可正常获取数据 rows = cur.fetchall() colnames = [desc[0] for desc in cur.description] df_result = pd.DataFrame(rows, columns=colnames) # 可选:跳过DROP语句的无结果集 cur.nextset() return df_result
nextset()方法会让游标移动到下一个结果集,返回True表示还有后续结果集,False表示已处理完所有语句。这里通过两次调用跳过INSERT和DROP的无结果执行,只处理中间的查询结果。
内容的提问来源于stack exchange,提问作者mike01010
相关产品推荐
相关产品推荐

