use*_*775 0 sql database oracle plsql sqlplus
我必须将 oracle db 中的表更新为 10k 的批次。
我试过这个:
BEGIN
WHILE (true) LOOP
UPDATE TOP (10000) CUSTOMERS SET ACTIVE = 'N' WHERE ACTIVE='Y';
IF sql%notfound THEN
EXIT;
END IF;
COMMIT;
END LOOP;
END;
Run Code Online (Sandbox Code Playgroud)
它不起作用,因为 plsql 不支持 top。
有什么建议?
你的 pl/SQL 块,使用 JVA 的建议,应该像这样完成(因为你是 pl/sql 的新手,我正在添加一些你可能感兴趣的语法建议):
BEGIN
-- WHILE (TRUE) can be omitted: "loop ... end loop;"
-- already is an endless loop
LOOP
UPDATE CUSTOMERS
SET ACTIVE = 'N'
WHERE ACTIVE='Y'
AND rownum <= 1000;
exit when sql%notfound; -- notice that exit accepts "when condition"
--IF sql%notfound THEN -- you can avoid a if/endif by using "exit when"
-- EXIT;
-- END IF;
COMMIT;
END LOOP;
commit; -- you missed this commit for the last iteration
END;
Run Code Online (Sandbox Code Playgroud)
不要试图将“commit”放在“exit when sql%notfound”之前:在“commit”之后 sql%notfound 总是假的,你的循环真的是无止境的。
让我指出,为了提高效率,这种方法需要对“ACTIVE”列进行索引!
如果您在“活动”列上没有索引,则每次“更新”都将被迫从头开始重新启动全表扫描,以找到下一个仍需要更新的 1000 条记录。
我提议的另一种方法使用了一些高级 PL/SQL 功能,作为学习者,您可能会感兴趣(rowid、“table of”、光标批量获取和“forall”)并且只对要更新的表进行一次扫描所以(在没有索引的情况下)它比以前的方法表现更好。请记住,如果您有索引,这会较慢(但使用 foralls、批量收集和 rowid 访问,它并没有那么慢),但在事情更复杂的情况下(例如:当 where 条件时,它可以派上用场)需要使用无法更快的复杂连接访问其他表中的数据)。在某些情况下,“where”是如此复杂和缓慢,以至于您真的不想使用“where rownum<=1000”方法一遍又一遍地重新执行它。
declare
type rowid_array is table of rowid;
ids rowid_array;
cursor cur is
select rowid as id
from CUSTOMERS
where ACTIVE='Y';
begin
open cur;
loop
fetch cur bulk collect into ids limit 1000;
exit when ids.count = 0;
forall c in ids.first .. ids.last
update CUSTOMERS set ACTIVE='N';
commit;
end loop;
end;
Run Code Online (Sandbox Code Playgroud)