0

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

我想在phone_no(old_phone_nonew_phone_no) 中取第一行并在employee_details 上执行更新语句,即 ( 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)
);

我正在考虑定期提交,因为我有大约 1000 万行EMPLOYEE_DETAILS,我们有很多行EMPOYEE_DETAILS用于单个电话号码,即OldPhone来自 table PHONE_NO

我不想打扰生产性能。如果有任何其他方法可以做到这一点,我很好。


以下方法是否有效。

DECLARE CURSOR all_phones IS SELECT OldPhone, NewPhone FROM PHONE_NO ORDER by OldPhone;

 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;

开始打开所有电话;FETCH all_phones BULK COLLECT INTO phone_olds, phone_news; 关闭所有电话;

 FOR inx1 IN 1..phone_olds.count LOOP
    begin
    loop
    update EMPLOYEE_DETAILS
    set PhoneNumber = phone_news(inx1)
    where PhoneNumber = phone_olds(inx1)
    and rowcount <= 10000;
    continue when sql%notfound; 
    commit;
    end loop
    commit;
 END LOOP;

结尾;

问候,杰伊。

4

4 回答 4

0

像这样的东西可能会起作用(未经测试),但我不确定您是否可以更新已用于 a 的列,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 的电话号码可以更新一次或两次。

于 2016-04-18T11:55:17.163 回答
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;
       /

对于更新的每一行,此代码将在任何更新后简单地将旧电话号码和新电话号码插入表中。

于 2016-04-18T11:56:00.683 回答
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;
于 2016-04-18T12:36:15.163 回答
-1

我会简单地更新它:

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。您可以使用纯唯一索引或主键或唯一键约束来执行此操作。)

于 2016-04-24T14:43:43.307 回答