如何检查存储过程中动态游标是否未检索到任何记录?
解决动态查询记录数判断的问题
看来你在PL/SQL存储过程里处理动态查询mmy_query的记录数判断时踩了坑——用prm_cursor%ROWTYPE时两种场景都返回0条,用SQL%ROWTYPE又始终返回1条,完全不符合你“经纪人不存在返回0条,存在则仅返回1条”的需求。我来帮你拆解问题,给出靠谱的解决方案。
先说说你之前两种方式的问题所在
1. 用prm_cursor%ROWTYPE的问题
你大概率是只声明了游标类型的变量,但没有正确打开游标、执行FETCH操作,也没判断游标状态(比如%FOUND)。如果只是定义了prm_cursor%ROWTYPE类型的变量,却没实际从游标中获取数据,游标属性会默认显示“无记录”,自然两种场景都返回0条。
2. 用SQL%ROWTYPE的问题
首先纠正一下,你应该是指SQL%ROWCOUNT吧?SQL%ROWCOUNT是用来统计最近一次SQL语句影响的行数,但它对动态SELECT的支持很有限:
- 如果你直接用
EXECUTE IMMEDIATE mmy_query而不带INTO,PL/SQL会直接报错(因为SELECT必须有接收变量); - 如果你用了
SELECT INTO,没找到记录时会抛出NO_DATA_FOUND异常,如果你没正确捕获这个异常,或者捕获后错误地设置了返回值,就会出现“始终显示1条”的错误。
正确的解决方案
根据你的需求(要么0条,要么1条),推荐两种靠谱的实现方式:
方式一:用EXECUTE IMMEDIATE ... INTO配合异常处理
这是最简洁的方式,直接利用PL/SQL的异常机制判断记录是否存在,同时确保只返回1条记录:
CREATE OR REPLACE PROCEDURE get_broker_record( p_mmy_query IN VARCHAR2, p_output_cursor OUT SYS_REFCURSOR, p_record_count OUT NUMBER ) AS -- 定义与查询结果匹配的记录类型(假设mmy_query对应某表/视图的结构) v_single_record your_table%ROWTYPE; BEGIN p_record_count := 0; -- 尝试获取单条记录 EXECUTE IMMEDIATE p_mmy_query INTO v_single_record; -- 走到这里说明成功获取1条记录 p_record_count := 1; -- 打开游标返回这条记录 OPEN p_output_cursor FOR p_mmy_query; EXCEPTION WHEN NO_DATA_FOUND THEN -- 无记录时返回空游标和0 OPEN p_output_cursor FOR SELECT * FROM DUAL WHERE 1 = 0; p_record_count := 0; WHEN TOO_MANY_ROWS THEN -- 查询返回多条,不符合需求,抛出自定义错误 RAISE_APPLICATION_ERROR(-20001, '查询返回多条记录,不符合预期要求'); END; /
方式二:用REF CURSOR手动判断记录数
如果你必须用游标实现,可以用动态游标(REF CURSOR)来手动控制获取过程:
CREATE OR REPLACE PROCEDURE get_broker_record( p_mmy_query IN VARCHAR2, p_output_cursor OUT SYS_REFCURSOR, p_record_count OUT NUMBER ) AS TYPE ref_cursor_type IS REF CURSOR; v_dynamic_cursor ref_cursor_type; v_single_record your_table%ROWTYPE; BEGIN p_record_count := 0; -- 打开动态游标 OPEN v_dynamic_cursor FOR p_mmy_query; -- 第一次获取记录 FETCH v_dynamic_cursor INTO v_single_record; IF v_dynamic_cursor%FOUND THEN -- 确认是否只有1条记录 FETCH v_dynamic_cursor INTO v_single_record; IF v_dynamic_cursor%FOUND THEN CLOSE v_dynamic_cursor; RAISE_APPLICATION_ERROR(-20001, '查询返回多条记录,不符合预期要求'); ELSE -- 只有1条记录,返回结果 p_record_count := 1; CLOSE v_dynamic_cursor; OPEN p_output_cursor FOR p_mmy_query; END IF; ELSE -- 无记录,返回空游标 CLOSE v_dynamic_cursor; OPEN p_output_cursor FOR SELECT * FROM DUAL WHERE 1 = 0; p_record_count := 0; END IF; END; /
关键注意点
- 确保
your_table%ROWTYPE和mmy_query的查询结果结构完全匹配,否则会抛出类型不匹配的错误; - 一定要处理
TOO_MANY_ROWS异常,保证查询不会返回多条记录; - 如果
mmy_query是动态拼接的,要注意SQL注入风险,尽量用绑定变量。
内容的提问来源于stack exchange,提问作者Roy Mathew
相关产品推荐
相关产品推荐

