2016-04-18 4 views
0

私はPL/SQLが初めてです。私はphone_noの最初の行をしたい、古い電話番号と新しい電話番号に別のテーブルPHONE_NOに格納されたテーブルemployee_detailsに電話番号を更新するための要件(カラムはold_phone_nonew_phone_noある)Pl sqlブロックは、定期的なコミットを使用してテーブルを一時テーブルの値で更新します。

old_phone_noを持っており、 new_phone_no)、定期的にコミットしてemployee_detailsの更新文(update employee_details set phone_no=new_phone_no where phone_no=old_phone_no)を実行します。

phone_noテーブルのすべての行を通過するまで、同じプロセスを続行する必要があります。

スタックオーバーフローのすべての専門家からの回答を検索します。

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で約10万行を持っており、私たちはテーブルPHONE_NOからOldPhoneすなわち、単一の電話番号をEMPOYEE_DETAILSに多くの行を持っているように私は、定期的なコミットを考えていました。

私は生産パフォーマンスを邪魔したくありません。私はそれを行う他の方法があれば大丈夫です。


下記の方法が有効かどうか。

DECLARE CURSOR のall_phones OldPhoneによってPHONE_NO 注文から SELECT OldPhone、NewPhone されます。

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はphone_olds、phone_newsに集約されます。 CLOSE 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; 

END;

よろしく、 Jay。

+0

[編集]あなたの質問や追加'両方のテーブルのためのtable'文を作成する(_formatted_テキストください、[なしスクリーンショット](http://meta.stackoverflow.com/questions/285551/why-may-i-not-upload-images-of-code-on-尋ねるときの質問/ 285557#285557))。 "* with periodic commits *"は通常、Oracleでは良い考えではありません。なぜストアドプロシージャが必要だと思いますか? –

+0

これは本当に難しい問題です。なぜなら、あなたは 'JOIN'のために働く列を更新しているからです。だから簡単な解決策はありません。本当に、単一の 'MERGE'ステートメントでもそれを処理することはできません。結合を単純化するために、 'employee_details'に' PersonID'を追加してください。 – Benoit

答えて

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回更新されます。

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

+0

これは、彼は私が、その後、 – Benoit

+0

申し訳ありませんが怖いです良い一日1持って望んでいるものではありません – Nicolas

0

あなたのDBインフラストラクチャが巨大な負荷を効率的に処理できない場合は、私が頭の中で一番上にあると考えることができる最良の方法は、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; 
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を避けるために、ユニーク宣言されなければならないので、制約が必要とされている。あなたは、プレーン一意のインデックスまたは他の主キーまたは一意キー制約でこれを行うことができます。)

関連する問題