Pl sql块使用临时表中的值定期提交来更新表

时间:2016-04-18 11:23:03

标签: plsql bulkupdate

我是PL / SQL的新手。我需要更新表employee_details中的电话号码,其中旧电话号码和新电话号码存储在另一个表phone_no中(列old_phone_nonew_phone_no

我想取phone_noold_phone_nonew_phone_no)中的第一行,并在employee_details上执行update语句,即(update employee_details set phone_no=new_phone_no where phone_no=old_phone_no)定期提交;

在我们遍历phone_no表中的所有行之前,应该继续相同的过程。

寻找Stack Overflow上所有专家的答案。

Create statements.
--Table which needs to be updated
CREATE TABLE EMPLOYEE_DETAILS
(
LastName varchar(255),
FirstName varchar(255),
Address varchar(255),
PhoneNumber varchar(255)
);

-- Temp Table which contains old and new phone numbers
CREATE TABLE PHONE_NO
(
PersonID int,
OldPhone varchar(255),
NewPhone varchar(255)
);

我在考虑定期提交,因为我在EMPLOYEE_DETAILS中有大约1000万行,EMPOYEE_DETAILS中有很多行用于单个电话号码,即来自表OldPhone的{​​{1}}

我不想打扰生产性能。如果还有其他方法可以做,我没事。

以下方法是否有效。

DECLARE      CURSOR all_phones IS          选择OldPhone,NewPhone          来自PHONE_NO          订购OldPhone;

PHONE_NO

BEGIN      打开all_phones;      FETCH all_phones BULK收集进入phone_olds,phone_news;      关闭all_phones;

 TYPE phone_old IS TABLE OF PHONE_NO.OldPhone%TYPE;
 TYPE phone_new IS TABLE OF PHONE_NO.NewPhone%TYPE;

 phone_olds phone_old;
 phone_news phone_new;
 inx1 PLS_INTEGER;

END;

此致 周杰伦。

4 个答案:

答案 0 :(得分:0)

这样的事情可能有用(未经过测试),但我不确定您是否可以更新已用于JOIN的列,因为它会使连接无效:

DECLARE
    CURSOR c IS SELECT pn.newphone
                  FROM employee_details ed
                  JOIN phone_no pn ON pn.oldphone = ed.phonenumber
                   FOR UPDATE OF ed.phonenumber;
    row_count INTEGER := 0;
    commit_frequency CONSTANT INTEGER := 10000;
BEGIN
    FOR rec IN c LOOP
        UPDATE employee_details
           SET phonenumber = rec.newphone
         WHERE CURRENT OF c;
        row_count := row_count + 1;

        IF MOD(row_count, commit_frequency) = 0 THEN
            COMMIT;
        END IF;
    END LOOP;
END;

你最好在employee_details.phonenumber上有一个索引!

同样,您可以执行以下操作,如果没有级联效果,则应该可以使用:

DECLARE
    commit_frequency CONSTANT INTEGER := 10000;
BEGIN
    FOR rec IN ( SELECT oldphone, newphone
                   FROM phone_no
               )
    LOOP
        UPDATE employee_details
           SET phonenumber = rec.newphone
         WHERE phonenumber = rec.oldphone;
        row_count := row_count + 1;

        IF MOD(row_count, commit_frequency) = 0 THEN
            COMMIT;
        END IF;
    END LOOP;
END;

级联效应存在以下问题:

     EMPLOYEE_DETAILS
name | surname | phonenumber
-----+---------+-------------
John | Doe     | +1 234 5678
Mike | Lee     | +1 098 7654

     PHONE_NO
oldphone    | newphone
------------+------------
+1 098 7654 | +1 357 9135
+1 234 5678 | +1 098 7654

在这里,John Doe的电话号码可以更新一次或两次。

答案 1 :(得分:0)

你知道触发器吗?在这种情况下,这将是最好的操作方式。触发是在特定条件之后执行的自动动作。在你的情况下,你可以做

CREATE OR REPLACE TRIGGER my_trigger
   AFTER UPDATE ON your_table
   FOR EACH ROW
       DECLARE
       BEGIN
           INSERT INTO phone_no
           (old_phone_no, new_phone_no)
           VALUES
           (OLD.phoneNumber, NEW.phoneNumber);

       END;
       /

对于每行更新,此代码只会在更新后在表格中插入旧电话号码和新电话号码。 希望它有所帮助! - Nic

答案 2 :(得分:0)

如果您的数据库基础架构不能有效处理大量负载,那么我能想到的最好的方法是使用LIMIT条件的BULK COLLECT方法。希望下面片段有帮助。我现在没有工作区,所以请原谅任何语法错误。

DECLARE
  TYPE lv_nphn  IS TABLE OF phone_number    .newphone%TYPE;
  TYPE lv_ophn  IS TABLE OF phone_number    .oldphone%TYPE;
  TYPE lv_empno IS TABLE OF employee_details.empno   %TYPE;
  lv_nph_tab   lv_nphn;
  lv_oph_tab   lv_ophn;
  lv_empno_tab lv_empno;
  CURSOR c
      IS SELECT pn.newphone,
                pn.oldphone,
                ed.empno
           FROM employee_details ed
           JOIN phone_no pn
             ON pn.oldphone = ed.phonenumber;
BEGIN
  OPEN C;
  LOOP
    FETCH C BULK COLLECT INTO lv_oph_tab,lv_nph_tab,lv_empno_tab LIMIT 10000;
    EXIT WHEN lv_nph_tab.COUNT = 0;

    FORALL I IN lv_nph_tab.FIRST..lv_nph_tab.LAST
        UPDATE employee_details
        SET phonenumber = lv_nph_tab(i)
        WHERE empno     = lv_empno_tab(i);
    COMMIT;
  END LOOP;
END;

答案 3 :(得分:0)

我只想更新它:

alter table phone_no add constraint phone_pk primary key(oldphone);

update ( select e.phonenumber, p.newphone
         from   employee_details e
                join phone_no p on p.oldphone = e.phonenumber )
set phonenumber = newphone;

然后担心你是否有足够的撤销资源等,如果它实际上是一个问题。

(需要约束,因为必须将oldphone声明为唯一才能避免 ORA-01779: cannot modify a column which maps to a non key-preserved table。您可以使用普通唯一索引或主键或唯一键约束来执行此操作。)