请找到以下代码。它不停止运行,没有操作或输出。
我做错了什么。
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;
/`
答案 0 :(得分:1)
正如@pcej所说,你缺少处理游标的一些部分。
通常,通常只有少数特定情况下,在您自己的代码中明确处理游标是个好主意。在几乎所有情况下,如果可能的话,最好在单个SQL语句中执行操作,或者如果实际需要循环,则使用隐式游标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'
)
/
或者,如果数据模型和主键是可以执行密钥保留连接的,则可能可以对连接执行更新。 (但我无法判断你的情况是否可行 - 我不知道数据模型; - )
另请注意,在所有情况下(包括您的代码和我的重写),如果customer_address
中有多个行cr = 'Y'
为同一c_id
,则会遇到问题。您可能希望查看您的数据模型,并确定在出现此类情况时您将要采取的措施。
答案 1 :(得分:0)
循环没有结束,因为你必须调用exit:
EXIT WHEN c1%NOTFOUND;
EXIT WHEN c2%NOTFOUND;
并记住关闭游标:
CLOSE c1;
CLOSE c2;
我不了解业务逻辑,因此无法帮助处理不采取行动的行为。