SQL 中的光标错误

Posted

技术标签:

【中文标题】SQL 中的光标错误【英文标题】:Cursor error in SQL 【发布时间】:2013-10-13 17:27:19 【问题描述】:

我正在尝试实现一个游标,在解决了许多错误之后,我终于到达了它运行的地步,但它进入了无限循环...... 我把表格的图像放在下面作为图像。 光标目标:计算保龄球平均值并存储在“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;

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

【问题讨论】:

为什么你的代码都是大写的? 我的教授认为大写字母更容易发现错误... :-),这是我听到的关于这个问题的最好和最差的答案!你这里有太多的循环,这就是原因。删除所有栏外的。 许多编程语言有多种编码风格,甚至没有一种说你所有的代码都应该大写。 @Ben,是的,我同意... 【参考方案1】:

在你的代码中添加空格可以让你更清楚你在做什么:

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 语句将显着提高效率。

【讨论】:

是的,当然,一次更新就足够了,但我必须将此作为项目工作,并且必须使用游标。我尝试运行优化的代码,但是仍然存在无限循环。我怀疑我在这里错过了一些非常重要的东西。有什么猜测吗??另外,我真的很感谢你的帮助。我知道我的代码不是那么干净,但是感谢你,我知道它比我想象的要糟糕得多...... 我怀疑你得到了一个无限循环@Sumedh。当您的光标选择表中的每一行时,这可能需要一些时间,尤其是如果您在 sid 上没有索引。 这里是working in a SQL Fiddle@Sumedh。 好的,现在它工作正常....不知道当时发生了什么。感谢所有这些帮助!

以上是关于SQL 中的光标错误的主要内容,如果未能解决你的问题,请参考以下文章

选择查询中的 PL/SQL 存储错误

不完整/格式错误的光标

带有光标的sqlite3执行完整性错误

编辑 Core Data 类实例字符串时,SwiftUI List 中的 TextField 出现光标定位错误?

将值插入记录类型表

vivado光标错位