Non Ending Loop in Cursor.

瘦欲@ 提交于 2019-12-11 20:17:34

问题


Please find the below code. It runs non stop with no operations or output.

what I'm doing wrong.

declare
cid number;
cadd number;
ctras number;
cr varchar(2);
cad number;
cursor c1 IS
select c_tras, c_id, c_add from customer_master;
cursor c2 IS
select c_address, cr from customer_address where c_id = cid;
begin
open c1;
open c2;
LOOP
fetch c1 into ctras, cid, cadd;
fetch c2 into cad, cr;
if cr='N'
THEN
update customer_master set c_address = (select c_address from customer_address where cr = 'Y' and c_id = cid) where c_tras = ctras;
END IF;
END LOOP;
END;
/`

回答1:


As @pcej answered you are missing some parts of handling cursors.

In general, it is normally only some few specific cases where it is a good idea to handle cursors explicitly in your own code. In almost all cases it is a better idea to preferably do things in a single SQL statement if at all possible, or if looping is actually needed then you use implicit cursor FOR loops, where the PL/SQL engine does all the cursor-handling for you.

Let's simplify your code step by step to show you what can be done...

First see how you can avoid declaring cursors, fetching into variables, and handling EXITs. This you can do by using the FOR loop:

begin
   for c1 in (
      select cm.c_tras, cm.c_id, cm.c_add
        from customer_master cm
   ) loop
      for c2 in (
         select ca.c_address, ca.cr
           from customer_address ca
          where ca.c_id = c1.c_id
      ) loop
         if c2.cr = 'N' then
            update customer_master cm
               set cm.c_address = (
                     select ca.c_address
                       from customer_address ca
                      where ca.cr = 'Y'
                        and ca.c_id = c1.c_id
                   )
             where cm.c_tras = c1.c_tras
         end if;
      end loop;
   end loop;
end;
/

Using the FOR loop allows the PL/SQL engine to handle the cursors for you - makes it much easier.

But the above is still very slow, as there are loops within loops and data is fetched for all rows, even if they are not needed.

Much better to avoid the loops within loops with a JOIN, and instead of IF statement use WHERE to only fetch the rows you actually need:

begin
   for c1 in (
      select cm.c_tras, cm.c_id, cm.c_add
           , ca.c_address, ca.cr
        from customer_master cm
        join customer_address ca
            on ca.c_id = cm.c_id
       where ca.cr = 'N'
   ) loop
      update customer_master cm
         set cm.c_address = (
               select ca.c_address
                 from customer_address ca
                where ca.cr = 'Y'
                  and ca.c_id = cm.c_id
             )
       where cm.c_tras = c1.c_tras
   end loop;
end;
/

But that is still not the best way, as @Alex Poole points out. It is even better not to do any looping at all, but instead do a single UPDATE statement that updates all the rows needed.

That could be something like this:

update customer_master cm
   set cm.c_address = (
         select ca.c_address
           from customer_address ca
          where ca.cr = 'Y'
            and ca.c_id = cm.c_id
       )
 where cm.c_tras in (
   select cm1.c_tras
     from customer_master cm1
     join customer_address ca
         on ca.c_id = cm1.c_id
    where ca.cr = 'N'
 )
/

Or if the datamodel and primary keys are such that you can do a key preserved join, it perhaps could be possible to do an update on a join. (But I cannot tell if that is possible in your case - I do not know the data model ;-)

Also note, that in all cases (both your code and my rewrites) you have problems if there are multiple rows in customer_address having cr = 'Y' for the same c_id. You may wish to review your datamodel and determine what you are going to if such cases arise.




回答2:


The loop is not ending because you have to invoke exit:

EXIT WHEN c1%NOTFOUND;
EXIT WHEN c2%NOTFOUND;

and remember about closing cursors:

CLOSE c1;
CLOSE c2;

I don't know the business logic so cannot help with no-action-behaviour.



来源:https://stackoverflow.com/questions/28145914/non-ending-loop-in-cursor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!