Non Ending Loop в курсоре.

Пожалуйста, найдите приведенный ниже код. Он работает без остановок без каких-либо операций или вывода.

что я делаю неправильно.

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; /` 

Поскольку @pcej ответил, что вам не хватает некоторых частей обработки курсоров.

В общем, обычно это всего лишь несколько конкретных случаев, когда неплохо обрабатывать курсоры явно в вашем собственном коде. Практически во всех случаях лучше всего делать что-либо в одном SQL-заявлении, если это вообще возможно, или если на самом деле требуется цикл, то вы используете неявные курсоры FOR FOR, где PL / SQL-движок выполняет всю обработку курсора для вы.

Давайте упростим ваш код шаг за шагом, чтобы показать вам, что можно сделать …

Сначала посмотрите, как можно избежать объявления курсоров, выборки в переменных и обработки EXIT. Это можно сделать с помощью цикла FOR:

 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; / 

Использование цикла FOR позволяет PL / SQL-движку обрабатывать курсоры для вас – делает его намного проще.

Но выше все еще очень медленно, поскольку в цикле есть петли, и данные извлекаются для всех строк, даже если они не нужны.

Гораздо лучше избегать циклов внутри циклов с помощью JOIN, а вместо оператора IF использовать WHERE, чтобы получать только нужные вам строки:

 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; / 

Но это все еще не самый лучший способ, как указывает @Alex Poole. Еще лучше не делать никаких циклов, но вместо этого нужно сделать одно заявление UPDATE, которое обновляет все необходимые строки.

Это может быть примерно так:

 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' ) / 

Или, если datamodel и первичные ключи таковы, что вы можете сделать ключевое сохраненное соединение, возможно, возможно было бы сделать обновление для соединения. (Но я не могу сказать, возможно ли это в вашем случае – я не знаю модель данных 😉

Также обратите внимание, что во всех случаях (как ваш код, так и мои перезаписи) возникают проблемы, если в customer_address имеется несколько строк с cr = 'Y' для одного и того же c_id . Вы можете просмотреть свою базу данных и определить, что собираетесь, если такие случаи возникнут.

Цикл не заканчивается, потому что вы должны вызывать exit:

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

и помните о закрытии курсоров:

 CLOSE c1; CLOSE c2; 

Я не знаю бизнес-логики, поэтому не могу помочь без действий.