0

カーソルを実装しようとしていますが、多くのエラーを解決した後、最終的に実行されるようになりましたが、無限ループに入ります...下の表の画像を画像として配置しました。カーソルの目的: ボウリングの平均を計算し、'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で実行しています。エラーを見つけるための支援をお願いします。前もって感謝します。

4

1 に答える 1

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 は(ほぼ)常に true と評価されます。
  • 7 と 8 ではループし、レコードがなくなると終了します。実際にレコードがあることを(2回)確認したので、このループを終了することはありません。

カーソルでこれを行うことを主張する場合は、ほとんどのコードを削除することができ、正常に動作するはずです:

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 ステートメントは、はるかに効果的です。

于 2013-10-13T17:45:57.607 に答える