具有联接和提交功能的Oracle SQL CURSOR更新

时间:2018-08-21 09:18:05

标签: 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 = '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后进行获取将返回错误。

有人有想法吗?我知道有一种无需“ FETCH”即可加入的方式,但我不知道如何。就像我之前说的,请仅提供代码帮助,而无需讨论更新和提交。

2 个答案:

答案 0 :(得分:0)

Exit必须在fetch之后,如果光标没有数据,则循环将终止。

在循环结束时,您可以按以下方式查询提交。 所以你的循环看起来像这样

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

答案 1 :(得分:0)

借助@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;