使用Join和Commit更新Oracle SQL游标
我想用另一个表的值更新一个表。但是:我需要在每50000行之后提交一次。我不想讨论为什么,我知道创建新表而不是更新的技巧,但这不是一个选项。我只需要查询方面的帮助 对于x行之后的更新,我发现以下内容:使用Join和Commit更新Oracle SQL游标,oracle,plsql,sql-update,cursor,Oracle,Plsql,Sql Update,Cursor,我想用另一个表的值更新一个表。但是:我需要在每50000行之后提交一次。我不想讨论为什么,我知道创建新表而不是更新的技巧,但这不是一个选项。我只需要查询方面的帮助 对于x行之后的更新,我发现以下内容: DECLARE i NUMBER := 0; CURSOR G1 IS SELECT * FROM test_new FOR UPDATE; BEGIN FOR c1 IN S1 LOOP UPDATE test SET col1 = 'so
DECLARE
i NUMBER := 0;
CURSOR G1 IS SELECT * FROM test_new
FOR UPDATE;
BEGIN
FOR c1 IN S1 LOOP
UPDATE test SET col1 = 'somevalue1'
WHERE CURRENT OF G1;
i := i + 1; -- Commits after every X number of records
IF i > 1000 THEN
COMMIT;
i := 0;
END IF;
END LOOP;
COMMIT;
END;
要使用另一个表更新表,此代码有效:
DECLARE
l_r_id test_new.id_customer%type;
l_r_name test_new.name%type;
i NUMBER := 0;
CURSOR CUR is select tnw.id_customer, tnw.name
from test_new tnw
, test tes
where tnw.id_customer = tes.id_customer
FOR UPDATE;
BEGIN
OPEN cur;
LOOP
FETCH cur
INTO l_r_id, l_r_name;
UPDATE test
set name = l_r_name
where test.id_customer = l_r_id;
i := i+1;
EXIT WHEN cur%notfound;
END LOOP;
commit;
END;
但我不知道该怎么做
IF i > 50000 THEN
COMMIT;
i := 0;
END IF;
输入代码。看来FETCH和Commit有问题。我从Oracle收到错误消息:
2) 如果游标是用FOR UPDATE子句打开的,则在发出COMMIT后获取将返回错误
有人有主意吗?我知道有一种方法可以不用“取回”就加入,但我不知道如何加入。就像我前面说的,请只在代码方面提供帮助,不要讨论更新和提交
退出
必须在获取
之后,如果光标没有数据,循环将终止
在循环结束时,您可以按如下方式查询提交。
所以你的循环可以像这样
LOOP
FETCH cur
INTO l_r_id, l_r_name;
EXIT WHEN cur%notfound;
UPDATE test
set name = l_r_name
where test.id_customer = l_r_id;
i := i+1;
if mod(i,50000) = 0 then
commit;
end if;
END LOOP;
另一个建议是定义一个记录集合。
使用表test\u new
中的数据填充集合。然后遍历此集合并进行更新
如果不进行测试,解决方案可能是这样的
DECLARE
TYPE tabTest IS TABLE OF test_new%ROWTYPE;
t_test tabTest;
i NUMBER := 0;
BEGIN
select tnw.*
bulk collect into t_test
from test_new tnw
, test tes
where tnw.id_customer = tes.id_customer
for indx in 1 .. t_test.count()
loop
UPDATE test
set name = t_test(indx).name
where test.id_customer = t_test(indx).id;
i := i+1;
if mod(i,50000) = 0 then
commit;
end if;
end loop;
commit;
END;
我在@hotfix帮助下的解决方案:
DECLARE
TYPE tabTest IS TABLE OF test_new%ROWTYPE;
t_test tabTest;
testcount number;
i NUMBER := 0;
BEGIN
select count(*) into testcount from test_new;
select tnw.*
bulk collect into t_test
from test_new tnw
, test tes
where tnw.id_customer = tes.id_customer;
FOR cur IN 1..testcount LOOP
UPDATE test
set name = t_test(cur).name
where test.id_customer = t_test(cur).id_customer;
i := i + 1; -- Commits after every X number of records
IF i > 50000 THEN
COMMIT;
i := 0;
END IF;
END LOOP;
COMMIT;
END;
:“错了,错了,错了。错得很……错得很厉害。”大概是这样吧?什么错误?此外,在第一个示例中,您的
g1
光标是从test_new中选择更新,但随后您更新了一个不同的表,其中当前的g1
,我希望给出该表ORA-01410:invalid ROWID
。在您的第二个示例中,我不清楚您为什么从游标FOR循环切换到更详细、效率更低的OPEN-FETCH-EXIT-CLOSE语法。老实说,我没有发现如何与第一个示例结合,第二个示例工作得非常好。我知道Tom Kyte对这个话题有自己的看法,他说得很清楚。我不会在ETL工作中使用它,但对于一个好的、经过良好测试的一次性更新来说,它非常有用。@WilliamRobertson是正确的for update
和current of
应该在同一个表上。第一个示例出现了相同的错误:2)如果游标是用for update子句打开的,则在发出COMMIT之后进行抓取将返回错误。“但是在第二个和一些更改的情况下,它可以工作。t_test.count()不起作用,但我设置了一个带有计数的变量。