SQL中的游标错误

时间:2013-10-13 17:27:20

标签: sql oracle10g

我正在尝试实现一个游标,&在解决了许多错误后,我终于达到了运行的程度,但它进入了无限循环...... 我把下面的图像作为图像。 光标的目标:计算保龄球平均值&存储在'bowling_avg'列中。 这是光标代码:

DECLARE
CURSOR  BOWL_AVG IS SELECT SID,MATCHES,BOWLING_AVG,WICKETS
FROM BOWLING_STATS ;
NSID BOWLING_STATS.SID%TYPE;
NMATCHES BOWLING_STATS.MATCHES%TYPE;
NBOWLING_AVG BOWLING_STATS.BOWLING_AVG%TYPE;
NWICKETS BOWLING_STATS.WICKETS%TYPE;

BEGIN
OPEN BOWL_AVG;
IF BOWL_AVG%ISOPEN THEN
LOOP
    FETCH BOWL_AVG INTO NSID,NMATCHES,NBOWLING_AVG,NWICKETS;
EXIT WHEN BOWL_AVG%NOTFOUND;
IF BOWL_AVG%FOUND THEN
LOOP
UPDATE BOWLING_STATS SET BOWLING_AVG=NWICKETS/NMATCHES WHERE SID=NSID ;
EXIT WHEN BOWL_AVG%NOTFOUND;
END LOOP;
END IF;
END LOOP;
ELSE
DBMS_OUTPUT.PUT_LINE('UNABLE TO OPEN CURSOR');
END IF; 
CLOSE BOWL_AVG;
END;

enter image description here

我在oracle数据库10g中运行它。 我在寻找错误时请求帮助。 提前谢谢。

1 个答案:

答案 0 :(得分:3)

在代码中添加空格可以让您更清楚自己所做的事情:

declare

   cursor bowl_avg is
   select sid, matches, bowling_avg, wickets
     from bowling_stats;

   nsid bowling_stats.sid%type;
   nmatches bowling_stats.matches%type;
   nbowling_avg bowling_stats.bowling_avg%type;
   nwickets bowling_stats.wickets%type;

begin

   -- 1. Open Cursor              
   open bowl_avg;

   -- 2. Check if Cursor is open
   if bowl_avg%isopen then
      -- 3. Loop
      loop
         -- 4. Get record
         fetch bowl_avg into nsid, nmatches, nbowling_avg, nwickets;
         -- 5. Exit if no records left
         exit when bowl_avg%notfound;

         -- 6. If there is a record
         if bowl_avg%found then
            -- 7. Loop
            loop
               update bowling_stats 
                  set bowling_avg = nwickets / nmatches 
                where sid = nsid;
               -- 8. Exit if there is no record.
               exit when bowl_avg%notfound;
            end loop;
         end if;

      end loop;
   else
      dbms_output.put_line('unable to open cursor');
   end if; 

   close bowl_avg;

end;
/

那里有许多矛盾。

  • 在1和2中,您打开一个光标,然后检查是否有一个打开的光标。如果光标未打开则会引发错误,因此您可以忽略此步骤。
  • 如果您无法获取新记录,请在5和6中退出,然后检查您是否有记录。这是一个矛盾,因此第6阶段将(almost)总是评估为真。
  • 你在7和8中循环
  • ,当你没有记录时退出。正如你刚刚检查过的那样(实际上有两次),你实际上有一个记录,你永远不会退出这个循环。

如果您坚持使用游标执行此操作,那么您可以删除大部分代码,它应该可以正常工作:

declare

   cursor bowl_avg is
   select sid, matches, bowling_avg, wickets
     from bowling_stats;

   nsid bowling_stats.sid%type;
   nmatches bowling_stats.matches%type;
   nbowling_avg bowling_stats.bowling_avg%type;
   nwickets bowling_stats.wickets%type;

begin

   -- 1. Open Cursor
   open bowl_avg;
   -- 2. Loop
   loop
      -- 3. Get record
      fetch bowl_avg into nsid, nmatches, nbowling_avg, nwickets;
      -- 4. Exit loop if there is no record.
      exit when bowl_avg%notfound;
      -- 5. Perform UPDATE statement.
      update bowling_stats 
         set bowling_avg = nwickets / nmatches 
       where sid = nsid;

   end loop;
   close bowl_avg;

end;
/

与往常一样,不使用循环,游标或PL / SQL的单个UPDATE语句将更加有效。