带有游标参数 (LOOP FETCH) 和 For 循环子查询的 PL/SQL 查询出错

Posted

技术标签:

【中文标题】带有游标参数 (LOOP FETCH) 和 For 循环子查询的 PL/SQL 查询出错【英文标题】:Errors on PL/SQL Queries with Cursor Parameters (LOOP FETCH) and For loop Subqueries 【发布时间】:2018-03-16 09:40:47 【问题描述】:

我想显示 country_id、country_name、region_id、highest_elevation、date_of_independence、population 的值 其中highest_elevation >1000 AND 5000000 也是有独立日的国家。 重要的是,region_id 的输出必须大于 1。

到目前为止,我已经尝试对其进行 PL/SQL 查询。但是,我发现了错误。我对查询进行了 2 种变体。带参数的游标使用 LOOP 和 FETCH 带有参数的游标也使用子查询和 FOR LOOP。

这是子查询的代码:

--pakai subqueries tp gak bisa
v_regid countries.region_id%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<1000 AND population >5000000 AND date_of_independence IS NOT NULL;
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;

第一次查询的错误:ORA-00900: invalid SQL statement

这里是带有参数的游标代码使用 LOOP 和 FETCH

--pakai cursor n parameter biasa
DECLARE
v_conid countries.country_id%TYPE;
v_coname countries.country_id%TYPE;
v_regid countries.region_id%TYPE;
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<1000 AND population >5000000 AND date_of_independence IS NOT NULL;
reccon cur_con%ROWTYPE;
BEGIN
SELECT country_id,country_name,region_id,highest_elevation,date_of_independence, population INTO v_conid,v_coname,v_regid,v_he,v_doi,v_pop
FROM countries;
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;

第二个查询的错误:ORA-01422:精确提取返回的行数超过了请求的行数

我的查询有什么问题?请帮帮我

【问题讨论】:

【参考方案1】:

您的第二个代码有问题,但代码 1 对我来说看起来不错。查看两个正确的工作版本:

代码 1:

DECLARE
  --pakai subqueries tp gak bisa
  --v_regid countries.region_id%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     <1000
    AND population            >5000000
    AND date_of_independence IS NOT NULL;
BEGIN
  FOR con_rec IN cur_con (v_regid)--<--Assuming you pass value of 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;

代码 2 : - 不需要执行两次选择查询。此外,当您在 begin 块内执行 Select 时,没有过滤条件,因此查询正在重新计算多行,您尝试将多行分配给单个变量。因此,您会遇到问题:ORA-01422: exact fetch returns more than requested number of rows。见下文

--pakai cursor n parameter biasa
DECLARE 
  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     <1000
    AND population            >5000000
    AND date_of_independence IS NOT NULL;

  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;

【讨论】:

好的,这两个查询都可以很好地编译,但是它没有提供信息。输出为:已处理语句。 0.01 秒 对我来说算法已经正确,但为什么它没有给出结果?哦,对了,顺便说一句,我使用 Oracle Apex Web 运行查询,因为架构就在那里。在 Oracle Apex 和 Oracle 11g 中运行有什么区别吗? 您需要检查是否设置了 serverout 或将 dbms_output.enable 放入您的块中。 正如我之前所说,我在 Oracle Apex Web 上运行了我的查询,因为所有的模式都在那里。当然,如果我在 Oracle 11g 上使用,我必须把服务器输出。仅供参考:我关注了您的查询,我已经运行了您的查询,但输出仍然“语句已处理。0.01 秒” @MayaRetnosari 不太确定,但似乎错误在于 Apex 设置。如果oracle编译了那么一定要看Apex端,

以上是关于带有游标参数 (LOOP FETCH) 和 For 循环子查询的 PL/SQL 查询出错的主要内容,如果未能解决你的问题,请参考以下文章

oracle数据库的存储过程中可以用到隐形游标。但是我不太明白为啥可以用 for in loop来完成对数据的处理。

带有参数化游标的嵌套 for 循环正在插入重复记录

使用 FETCH 的 PL/SQL 游标 FOR 循环

oracle For loop,隐式游标

在 CURSOR FOR LOOP 中使用游标属性

oracle for loop循环以及游标循环