尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
postgresql 游标(cursor)使用指南:从声明到 FETCH 的完整实践
1. 为什么大批量数据处理绕不开 PostgreSQL 游标如果你写过SELECT * FROM 大表然后一次性把结果全塞进内存多半遇到过查询变慢、连接被占满甚至服务直接 OOM 的情况。PostgreSQL 游标cursor就是解决这类问题的核心工具它把一个大结果集封装成一个可逐行、分批读取的句柄你每次只取一部分数据内存占用可控处理逻辑也能写得更清晰。简单说游标能帮你做三件事第一对海量结果集分批处理避免一次性加载第二在存储过程或函数里对每一行做单独加工比如逐行校验、逐行写日志第三让函数返回一个游标变量调用方自己决定怎么取数这是返回大数据集时非常实用的方式。它适合谁适合正在写 PL/pgSQL 存储过程、做数据清洗、做批量任务调度的后端和 DBA。如果你只是做简单查询游标反而多余但只要涉及“逐行处理 大数据量”它就是绕不开的基本功。整条链路其实就五步声明DECLARE→ 打开OPEN→ 取数FETCH→ 判断是否还有行 → 关闭CLOSE。下面我按这个顺序把每一步的语法、可复制配置和踩坑点都拆开讲。2. 声明游标REFCURSOR 与绑定游标的区别及声明语法声明是游标生命周期的起点。PostgreSQL 提供两种声明方式理解它们的差异能帮你少走很多弯路。第一种是非绑定游标用REFCURSOR类型声明声明时不绑定任何查询DECLARE my_cursor REFCURSOR;这种游标初始值是 null打开时才指定查询灵活性高适合动态 SQL 场景。但要注意在递归函数里定义游标时必须用非绑定游标否则会报cursor already in use。第二种是绑定游标声明时就把查询绑死语法如下cursor_name [ [NO] SCROLL ] CURSOR [(name datatype, name datatype, ...)] FOR query;拆开看cursor_name是游标名SCROLL表示游标可以前后滚动NO SCROLL则不能回滚CURSOR是关键字括号里是参数列表参数在打开游标时被替换FOR后面跟任意合法的 SELECT 子句。举个实际例子DECLARE cur_films CURSOR FOR SELECT * FROM film; cur_films2 CURSOR (year integer) FOR SELECT * FROM film WHERE release_year year;cur_films封装了 film 表所有记录cur_films2带一个 year 参数只取指定发行年份的记录。绑定游标在声明时就被初始化为一个字符串值官方叫 portal name后续保持不变而非绑定游标初始为 null打开时会接受一个自动生成的唯一名称。这里有个容易忽略的点绑定游标的参数是在 OPEN 时传入的不是声明时。所以声明里写(year integer)只是定义形参真正赋值在打开阶段。理解这一点后面看 OPEN 语法就不会懵。3. 打开与取数OPEN、FETCH、MOVE 的可复制配置打开游标是让它真正开始工作的关键一步绑定和非绑定游标的打开方式不同。打开非绑定游标必须在 OPEN 时指定查询OPEN unbound_cursor_variable [ [NO] SCROLL ] FOR query;例如OPEN my_cursor FOR SELECT * FROM city WHERE counter p_country;如果要执行动态查询用FOR EXECUTEOPEN unbound_cursor_variable [ [NO] SCROLL ] FOR EXECUTE query_string [USING expression [, ...]];实际用法query : SELECT * FROM city ORDER BY $1; OPEN cur_city FOR EXECUTE query USING sort_field;打开绑定游标就简单多了因为查询已经绑好只需传参数OPEN cursor_variable [ (name : value, name : value, ...) ];对应前面的声明OPEN cur_films; OPEN cur_films2(year : 2005);打开之后进入取数阶段。FETCH 语法FETCH [ direction { FROM | IN } ] cursor_variable INTO target_variable;target_variable可以是 record 类型、row 变量或逗号分隔的变量列表。如果没取到行目标变量为 null。方向不写默认是 NEXT可选值包括 NEXT、LAST、PRIOR、FIRST、ABSOLUTE count、RELATIVE count、FORWARD、BACKWARD。注意只有 SCROLL 声明的游标才能 FORWARD 和 BACKWARD。FETCH cur_films INTO row_film; FETCH LAST FROM cur_films INTO title, release_year;如果只想移动游标不返回数据用 MOVEMOVE [ direction { FROM | IN } ] cursor_variable; MOVE cur_films2; MOVE LAST FROM cur_films; MOVE RELATIVE -1 FROM cur_films; MOVE FORWARD 3 FROM cur_films;游标定位后还能直接更新或删除当前行UPDATE table_name SET column value, ... WHERE CURRENT OF cursor_variable; DELETE FROM table_name WHERE CURRENT OF cursor_variable;例如UPDATE film SET release_year p_year WHERE CURRENT OF cur_films;这套组合在批量修正数据时特别顺手不用先查主键再回写。4. 完整循环取数示例与执行验证步骤光看语法不够下面给一个能直接跑的完整函数。先建表插数据CREATE TABLE foo ( fooid int, fooname text ); INSERT INTO foo VALUES (1, hi), (1, hello), (2, world);然后创建函数用绑定游标循环取数并拼接结果CREATE OR REPLACE FUNCTION get_fooname1(id integer) RETURNS text AS $$ DECLARE title text DEFAULT fooname ; f_name record; cur_fname CURSOR (id integer) FOR SELECT fooname, fooid FROM foo WHERE fooid id; BEGIN OPEN cur_fname(id); LOOP FETCH cur_fname INTO f_name; EXIT WHEN NOT FOUND; title : title || : || f_name.fooname; END LOOP; CLOSE cur_fname; RETURN title; END; $$ LANGUAGE plpgsql;执行验证SELECT * FROM get_fooname1(1);预期输出get_fooname1 -------------- fooname :hi:hello (1 row)这里有几个关键点值得强调。EXIT WHEN NOT FOUND是循环退出的标准写法FETCH 取不到行时 FOUND 会变成 false。CLOSE一定要执行否则游标占用的资源不会释放同一会话里重复打开同名游标还可能报错。另外函数返回 text 只是演示真实场景里你可以返回 REFCURSOR让调用方自己 FETCH。如果你在存储过程里处理几十万行建议配合FETCH FORWARD 1000分批取每批处理完再取下一批内存曲线会平稳很多。5. 常见报错排查cursor already in use 与 not found 处理游标用起来不难但几个报错很典型我按实际遇到的频率排一下。第一个是cursor already in use。原因通常是递归函数里用了绑定游标或者同一会话里重复 OPEN 了同名游标却没 CLOSE。解决办法递归场景改用非绑定游标 REFCURSOR非递归场景确保每次 OPEN 前对应游标已 CLOSE或者用不同名称。第二个是cursor unnamed portal 1 does not exist。多出现在非绑定游标打开后名称处理不当或者事务结束后游标自动失效。PostgreSQL 里游标默认只在当前事务内有效事务提交或回滚后游标就没了。如果你需要跨事务得用WITH HOLD但要注意 WITH HOLD 游标在事务结束后才物化行为有差异。第三个是 FETCH 后变量为 null 却没退出循环。这通常是没写EXIT WHEN NOT FOUND或者把 FOUND 判断写在了 FETCH 之前。正确顺序永远是先 FETCH再判断 FOUND。第四个是DECLARE CURSOR can only be used in transaction blocks。在自动提交模式下直接 DECLARE 会报这个需要显式BEGIN;开启事务块。排查时建议先确认三件事游标是否在事务块内、是否已 CLOSE、方向关键字是否和 SCROLL 声明匹配。把这三条对齐大部分报错都能定位。6. 把游标逻辑落到真实查询里游标真正的价值不在语法本身而在于它让你能对每一行做精细控制。我自己的习惯是数据量小于几千行直接用普通查询或FOR ... IN SELECT循环超过这个量级、或者需要分批提交、逐行调用外部逻辑时才上显式游标。如果你在写 PL/pgSQL 时经常需要调试取数过程可以配合模型对话把函数逻辑先跑通再贴回数据库执行省去反复改函数重建的时间。需要管理多个环境的 Key 时API Keys 页面能集中处理。长期做数据管道和 Agent 类任务的话Coding Plan 对持续编码场景更合适。接入细节可以直接查接入文档里面有完整的 Base URL、Key 和 Model ID 配置说明。最后留一个实用技巧调试游标循环时在 LOOP 里临时加一句RAISE NOTICE row: %, f_name;能直观看到每一行取到什么比猜变量值快得多。
RELATED

相关推荐

吉利6.4亿入股蔚来能源、车网互动定5000万千瓦:补能进入“生态战“时代

吉利6.4亿入股蔚来能源、车网互动定5000万千瓦:补能进入“生态战“时代

吉利以易易互联100%股权及6.4亿元现金入股蔚来能源持股30%、蔚来认购浩瀚能源10%,双方充电资源全面互联互通、共建统一C端换电标准;"十五五"规划明确车网互动聚合可调充电规模2030年达5000万千瓦;蔚来国庆加电超207万次、单日换电超…

📅 2026/10/12 15:39:25
通信工程就业真相:6类技术动作+3大隐性门槛

通信工程就业真相:6类技术动作+3大隐性门槛

简介:本资源是一份面向通信工程专业本科生及应届毕业生的就业指导文档,聚焦5G时代下高需求、高成长性的核心职业路径。内容系统梳理SP产品经理与电信交换工程师两大主流方向,涵盖职业定义、典型工作内容、硬性能力要求(如No.7信令…

📅 2026/10/12 15:34:25
【Agent】DeerFlow:长程任务执行Runtime 的沙箱与状态管理拆解

【Agent】DeerFlow:长程任务执行Runtime 的沙箱与状态管理拆解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/12 15:34:25
MORE NEWS

更多资讯

📰

OpenClaw 2.7.9 对接飞书机器人完整分步实操教程(含安装包)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

C语言循环控制:break、continue、goto的跳转机制与实战陷阱

不少学C语言的朋友走到系列第11篇,已经把顺序、分支这些基础结构拿捏得差不多了,一进入循环嵌套的实战场景就发愁:到底什么时候用break,什么时候用continue,那个被无数人念叨“不要用”的goto又是怎么回事。这篇就把循…

📰

AI编程工具深入使用:从代码补全到稳定高效工作流

1. 先把AI编程工具用明白:核心能力与选型思路AI编程工具这两年几乎是每个开发者的日常话题,但绝大多数人还停留在"让AI帮我写个函数、补全一段代码"的层面。跟你实话实说,我在早期也是这样,装上某款AI编程助手之后&…

📰

AI编程工具实战:从需求到上线的人机协作方法论

说实话,AI编程工具刚火起来那阵子,我心里是带着问号的。代码补全工具我试过,结论是“偶尔惊艳,经常添乱”。后来真正改变我想法的,不是哪一款工具突然变得多聪明,而是我调整了使用方式——从“让AI替我写代…

📰

TCN时间卷积神经网络在MATLAB故障诊断中的落地实践

简介:基于TCN时间卷积神经网络实现故障诊断的Matlab资源包,面向计算机、电子信息工程、数学等专业大学生,适用于课程设计、期末大作业或毕业设计。资源共8个文件,包含m主程序、xlsx案例数据集、png运行结果图和zip完整源码&#x…

📰

零基础AI漫剧制作全流程:从文案到量产的核心链路

1. 我在创作营里学到了什么:AI漫剧的核心生产链路先说结论:零基础做AI漫剧,最难的不是技术,而是“不知道完整流程长什么样”。我参加这个创作营之前,以为AI漫剧就是“AI画图配音”这么简单,真正上手才发现&…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬