带游标参数的PL/SQL查询(LOOP FETCH与FOR循环子查询)报错排查
PL/SQL游标报错排查与修复
咱们先逐个拆解你遇到的两个报错问题,顺便把逻辑上的坑也给你指出来:
一、子查询+FOR循环代码的问题(ORA-00900)
你这段代码的核心问题是变量v_regid没有在DECLARE块里声明,PL/SQL要求所有变量必须在DECLARE部分定义后才能使用。另外还有个逻辑硬伤:highest_elevation >1000 AND highest_elevation<1000这个条件完全矛盾,不可能有任何数据满足,得先确认你的需求是不是写错了(比如是不是>1000 OR <1000?或者范围写错了?)。
修复后的代码应该加上DECLARE块,同时修正矛盾条件(这里假设你是想写一个合理范围,比如>1000 AND <5000,你可以根据实际需求调整):
DECLARE v_regid countries.region_id%TYPE := 2; -- 这里给个合法的region_id值,比如2,你可以按需修改 CURSOR cur_con (pregid NUMBER) IS SELECT country_id, country_name, region_id, highest_elevation, date_of_independence, population FROM countries WHERE region_id = pregid AND highest_elevation > 1000 -- 修正矛盾条件,替换成你实际需要的范围 AND highest_elevation < 5000 AND population > 5000000 AND date_of_independence IS NOT NULL AND region_id > 1; -- 加上你要求的region_id>1的条件 BEGIN FOR con_rec IN cur_con (v_regid) LOOP DBMS_OUTPUT.PUT_LINE ( ' ' ); DBMS_OUTPUT.PUT_LINE ( ' ============================================= ' ); DBMS_OUTPUT.PUT_LINE ( ' ID Negara : ' || con_rec.country_id ); DBMS_OUTPUT.PUT_LINE ( ' Nama Negara : ' || con_rec.country_name ); DBMS_OUTPUT.PUT_LINE ( ' ID Region : ' || con_rec.region_id ); DBMS_OUTPUT.PUT_LINE ( ' Ketinggian yang tertinggi : ' || con_rec.highest_elevation ); DBMS_OUTPUT.PUT_LINE ( ' Hari kemerdekaan : '|| con_rec.date_of_independence ); DBMS_OUTPUT.PUT_LINE ( ' Populasi : ' ||con_rec.population ); DBMS_OUTPUT.PUT_LINE ( ' ============================================= ' ); DBMS_OUTPUT.PUT_LINE ( ' ' ); END LOOP; END; /
二、LOOP+FETCH方式代码的问题(ORA-01422)
这段代码有三个明显问题:
- 多余的SELECT INTO语句:
SELECT ... INTO v_conid,... FROM countries;没有WHERE条件,会返回整个表的所有行,但SELECT INTO只能接收一行数据,直接抛出ORA-01422错误。其实你根本不需要这个语句,游标本身会读取数据。 - 变量类型错误:
v_coname countries.country_id%TYPE;这里v_coname是用来存国家名称的,应该写成v_coname countries.country_name%TYPE;,你写错成了country_id的类型。 - 同样存在highest_elevation的矛盾条件,以及漏加了
region_id>1的条件。
修复后的代码如下:
DECLARE v_conid countries.country_id%TYPE; v_coname countries.country_name%TYPE; -- 修正类型错误 v_regid countries.region_id%TYPE := 2; -- 给合法的region_id值,按需修改 v_he countries.highest_elevation%TYPE; v_doi countries.date_of_independence%TYPE; v_pop countries.population%TYPE; CURSOR cur_con (pregid NUMBER) IS SELECT country_id, country_name, region_id, highest_elevation, date_of_independence, population FROM countries WHERE region_id = pregid AND highest_elevation > 1000 -- 修正矛盾条件,替换成你实际需要的范围 AND highest_elevation < 5000 AND population > 5000000 AND date_of_independence IS NOT NULL AND region_id > 1; -- 加上region_id>1的要求 reccon cur_con%ROWTYPE; BEGIN OPEN cur_con(v_regid); LOOP FETCH cur_con INTO reccon; EXIT WHEN cur_con%NOTFOUND; DBMS_OUTPUT.PUT_LINE ( ' ' ); DBMS_OUTPUT.PUT_LINE ( ' ============================================= ' ); DBMS_OUTPUT.PUT_LINE ( ' ID Negara : ' || reccon.country_id ); DBMS_OUTPUT.PUT_LINE ( ' Nama Negara : ' || reccon.country_name ); DBMS_OUTPUT.PUT_LINE ( ' ID Region : ' || reccon.region_id ); DBMS_OUTPUT.PUT_LINE ( ' Ketinggian yang tertinggi : ' || reccon.highest_elevation ); DBMS_OUTPUT.PUT_LINE ( ' Hari kemerdekaan : '|| reccon.date_of_independence ); DBMS_OUTPUT.PUT_LINE ( ' Populasi : ' ||reccon.population ); DBMS_OUTPUT.PUT_LINE ( ' ============================================= ' ); DBMS_OUTPUT.PUT_LINE ( ' ' ); END LOOP; CLOSE cur_con; END; /
额外提醒
- 那个
highest_elevation >1000 AND highest_elevation<1000的条件一定要修正,否则不管其他条件怎么对,都查不到任何数据。 - 如果你的需求是要查询所有region_id>1的国家,而不是指定某个pregid,那可以把游标改成不带参数的,直接在WHERE里写
region_id>1即可,不用传参数。
内容的提问来源于stack exchange,提问作者user7599364
相关产品推荐
相关产品推荐

