Как @pcej ответил, что вам не хватает некоторых частей обработки курсоров.
В целом, обычно это всего лишь несколько конкретных случаев, когда хорошая идея обрабатывать курсоры явно в вашем собственном коде. Практически во всех случаях лучше всего делать что-либо в одном SQL-заявлении, если это вообще возможно, или если на самом деле требуется цикл, то вы используете неявные курсоры FOR FOR, где PL/SQL-движок выполняет всю обработку курсора для вы.
Давайте упростить ваш шаг за шагом код, чтобы показать вам, что можно сделать ...
Во-первых, как можно избежать объявления курсоров выборки в переменные, и обработку выходов. Это можно сделать с помощью цикла 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;
/
Использование для цикла позволяет/SQL двигатель PL для обработки курсоров для вас - делает его гораздо проще.
Но выше все еще очень медленно, так как в цикле есть петли, и данные извлекаются для всех строк, даже если они не нужны.
Гораздо лучше, чтобы избежать петли внутри петли с JOIN, и вместо IF использовать оператор WHERE только Fetch строки, которые на самом деле нужно:
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;
/
Но это еще не самый лучший способ, как и @ Алекс Пул отмечает. Еще лучше не делать никаких циклов, но вместо этого нужно сделать одно заявление 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
. Вы можете просмотреть свою базу данных и определить, что собираетесь, если такие случаи возникнут.
Как и не показано, как показано в pcej, 'cid' имеет значение null в точке, которую вы открываете' c2', и это не будет автоматически обновляться, когда вы получаете 'c1'. Ваш первый выбор 'c2' никогда не получит запись, поэтому вы сразу же выйдете. Вам нужны вложенные циклы, а не один цикл.Но вы можете сделать это с помощью одного курсора с соединением; и может использовать одно коррелированное обновление, вам вообще не нужен PL/SQL. –