为什么我的光标无法正常工作?

时间:2016-02-11 18:07:12

标签: plsql cursor procedure

我设置了一个游标来获取我的过程结果中的多行。但是,它似乎通过生成此错误消息不起作用: “01422. 00000 - ”确切的提取返回超过请求的行数“ *原因:精确提取中指定的数字小于返回的行数。 *操作:重写查询或更改请求的行数“

代码的其他部分没有问题,因为当我只有一条记录时我试过,它运行正常。但是当有多个记录时,我的光标似乎不起作用。那是为什么?

set serveroutput on

declare
   get_term scores.term%type;
   get_sectno scores.sectno%type;
   get_sid scores.sid%type;
   get_score scores.points%type;
   status boolean;

   procedure total_score (aterm in out scores.term%type,
                 asectno in out scores.sectno%type,
                 asid out scores.sid%type,
                 ascore out scores.points%type,
           status out boolean)
   is
   cursor find is 
      select scores.term, scores.sectno, sid, sum(points/maxpoints*weight)
      from scores, components
      where scores.term=components.term
      and scores.sectno=components.sectno
      group by scores.term, scores.sectno, sid;
   find_rec find%rowtype;   
   begin
      open find;
      fetch find into find_rec;
      while find%found loop
         select scores.term, scores.sectno, sid, sum(points/maxpoints*weight)
         into aterm, asectno, asid, ascore
         from scores, components
         where scores.term=components.term
         and scores.term=aterm
         and scores.sectno=components.sectno
         and scores.sectno=asectno
         and scores.compname=components.compname
         group by scores.term, scores.sectno, sid;
         status:=true;
         fetch find into find_rec;
      end loop;
      close find;
   exception
      when no_data_found then
         status:=false;
   end;
begin
   get_term:='F12';
   get_sectno:='1031';
   total_score (get_term, get_sectno, get_sid, get_score, status);
   if (status) then
      dbms_output.put_line(get_term||' '||get_sectno||' '||get_sid||' '||get_score);
   else
      dbms_output.put_line('Record not found.');
   end if;
end;

1 个答案:

答案 0 :(得分:0)

我会改写如下:

open find;
loop
 fetch find into find_rec;
 Exit when find%NOTFOUND;
...
end loop;
close find;

但是,如果您不在内部选择中使用其值,为什么要打开此光标? 但是,我认为生成错误是因为游标内部的select会在一次或多次迭代中返回两行或更多行。 有关更多信息,请参阅,例如http://www.oracle.com/technetwork/issue-archive/2013/13-mar/o23plsql-1906474.html。再见,伊戈尔

更新

CREATE TABLE SCORES(SID INTEGER, TERM VARCHAR2(10), SECTNO VARCHAR2(10), COMPNAME VARCHAR2(50));
CREATE TABLE COMPONENTS(TERM VARCHAR2(10), SECTNO VARCHAR2(10), COMPNAME VARCHAR2(50), POINTS INTEGER, MAXPOINTS INTEGER, WEIGHT INTEGER);



INSERT ALL
INTO SCORES VALUES(1,'AAA', 'BBB', 'CCC')
INTO SCORES VALUES(5,'AAA', 'BBB', 'CCC')
INTO SCORES VALUES(2,'DDD', 'EEE', 'FFF')
INTO SCORES VALUES(3,'GGG', 'HHH', 'III')
SELECT * FROM DUAL;


INSERT ALL
INTO COMPONENTS VALUES('AAA', 'BBB', 'CCC', 1, 2, 3)
INTO COMPONENTS VALUES('DDD', 'EEE', 'FFF', 4, 5, 6)
INTO COMPONENTS VALUES('GGG', 'HHH', 'III', 7, 8, 9)
SELECT * FROM DUAL;

COMMIT;



CREATE OR REPLACE PROCEDURE TOTAL_SCORE (ATERM in OUT SCORES.TERM%type,
                 ASECTNO in OUT SCORES.SECTNO%type) AS
 cursor find (cpAterm VARCHAR2, cpAsectno VARCHAR2) is 
      select scores.term, scores.sectno, sid, sum(points/maxpoints*weight) AS SUM_SCORE
         from scores RIGHT JOIN components ON
         scores.term=components.term
         and scores.sectno=components.sectno
         and scores.compname=components.compname
         WHERE
          scores.term=cpAterm
          AND scores.sectno=cpAsectno
         group by scores.term, scores.sectno, sid;
   find_rec find%rowtype; 

   counter INTEGER:=0;

BEGIN
 open find(ATERM, ASECTNO);
 LOOP
       fetch find into find_rec;
      exit when find%notfound;
      --DBMS_OUTPUT.PUT_LINE(find_rec.TERM||' '||find_rec.sectno||' '||find_rec.SID||' '||find_rec.SUM_SCORE);
      if (find_rec.term IS NOT NULL) then
      dbms_output.put_line(find_rec.TERM||' '||find_rec.sectno||' '||find_rec.SID||' '||find_rec.SUM_SCORE);
      counter:=counter+1;
      END IF;
      end loop;
      close find;
      if counter = 0 then
      dbms_output.put_line('NO DATA FOUND FOR: ' || ATERM || ', ' || ASECTNO);
      end if;

END;
/

SET SERVEROUTPUT ON
DECLARE
 get_term VARCHAR2(10);
 get_sectno VARCHAR2(10);
begin
   get_term:='AAA';
   get_sectno:='BBB';
   total_score (get_term, get_sectno);
  END;
/

DROP TABLE SCORES;
DROP TABLE COMPONENTS;