0

PL/SQL は初めてです。古い電話番号と新しい電話番号が別のテーブル phone_no に格納されているテーブル employee_details の電話番号を更新する必要があります (列はold_phone_noとですnew_phone_no)

phone_no( old_phone_noand ) の最初の行を取得し、定期的なコミットを使用しnew_phone_noて、employee_details ie ( ) で 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)
);

約1,000万行あり、単一の電話番号、つまりテーブルからEMPLOYEE_DETAILS多くの行があるため、定期的なコミットを考えていました。EMPOYEE_DETAILSOldPhonePHONE_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;

BEGIN OPEN all_phones; FETCH all_phones BULK COLLECT INTO phone_olds, phone_news; all_phones を閉じます。

 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

このようなものはおそらく機能する可能性があります(テストされていません)が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 回または 2 回更新される可能性があります。

于 2016-04-18T11:55:17.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 に答える