You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

执行含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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 02:37:27