2016-07-19 1 views
0

私は同じテーブルを繰り返すforループを入れました。内部ループでは、同じテーブルの列を更新します。しかしforループ条件では、私は更新された列をチェックし、私はこの列を始めからではなく動的にチェックする必要があるので、forループの反復はおそらく大幅に減少するでしょう。oracleのforループ文に対するupdate文の影響はありますか?

私はこれを正しくやっているのですか?for文は更新された列を見ませんか?

declare 
control number(1); 
dup number(10); 
res varchar2(5);--TRUE or FALSE 

BEGIN 
dup :=0; 
control :=0; 
FOR aRow IN (SELECT MI_PRINX, geoloc,durum, ROWID FROM ORAHAN where durum=0)  
LOOP 
FOR bRow IN (SELECT MI_PRINX, geoloc, ROWID FROM ORAHAN WHERE ROWID>aRow.ROWID AND durum=0) 
    LOOP 
    BEGIN 
     --dbms_output.put_line('aRow' || aRow.Mi_Prinx || ' bRow' || bRow.Mi_Prinx); 
    select SDO_GEOM.RELATE(aRow.geoloc,'anyinteract', bRow.Geoloc,0.02) into res from dual; 
    if (res='TRUE') 
     THEN 
     Insert INTO ORAHANCROSSES values (aRow.MI_PRINX,bRow.MI_PRINX); 
     UPDATE ORAHAN SET DURUM=1 where rowid=bRow.Rowid; 
     control :=1; 
     --dbms_output.put_line(' added'); 
    END IF; 
    EXCEPTION 
     WHEN DUP_VAL_ON_INDEX 
     THEN 
      dup := dup+1; 
      --dbms_output.put_line('duplicate'); 
      --continue; 
    END; 
    END LOOP; 
    IF(control =1) 
    THEN 
     UPDATE ORAHAN SET DURUM=1 WHERE rowid=aRow.Rowid; 
    END IF; 
    control :=0; 
END LOOP; 
dbms_output.put_line('duplicate: '||dup); 
END ; 

注:私は、Oracle 11gのとPL/SQL Developerの 申し訳ありませんが私の英語を使用しています。

+0

'ROWID> aRow.ROWID'で何を達成しようとしていますか? Oracleの 'ROWID'は多かれ少なかれランダムな文字列です。 'ROWID> aRow.ROWID'の結果は決定されません。あなたがレコードをロックしない限り、与えられたレコードのROWIDは変更されるかもしれません。しかし、これは通常行を手動でロックすることをお勧めしません。 –

+0

私はrowidの使い方が間違っていることを認識しています。私の目的は、外側のループですべての行を1つずつチェックしています。内部ループでは、私はちょうど外側のループで選択された行からさらに行をチェックする必要があります。 –

答えて

1

はい、FORステートメントは、クエリの開始時と同じようにすべてのデータを表示するため、更新されたDURUM列は表示されません。これは読取り一貫性と呼ばれ、Oracleは生成されたUNDOデータを使用してこれを実現します。つまり、FORループが進んでベーステーブルが更新されるにつれて、より多くの作業(=より低速で実行する)が必要になるでしょう!

UNDO表領域が使い果たされたときに、実装が最終的にORA-01555:スナップショットが古すぎるというエラーになります。

SQL MERGE文を使用するほうがずっと速く実行する方がよいでしょう。

例:

Merge Into ORAHANCROSSES C 
Using (Select aROW.MI_PRINX aROW_MI_PRIX, 
       aROW.GEOLOC aROW_GEOLOC, 
       bROW.MI_PRINX bROW_MI_PRIX, 
       bROW.GEOLOC bROW_GEOLOC, 
       SDO_GEOM.RELATE(aRow.geoloc,'anyinteract', bRow.Geoloc,0.02) RES 
     From ORAHAN aROW, 
       ORAHAN bROW 
     Where aROW.ROWID < bROW.ROWID 
     ) Q 
On (C.MI_PRIX1 = Q.aROW_MI_PRIX 
    and C.MI_PRIX2 = Q.bROW_MI_PRIX) 
When Matched Then 
    Delete Where Q.RES = 'FALSE' 
When Not Matched Then 
    Insert Values (Q.aROW_MI_PRIX, Q.bROW_MI_PRIX) 
    Where Q.RES = 'TRUE' 
; 

私はあなたが(この場合はMI_PRINX)、特定の順序を使用するには

かかわらROWID>aRow.ROWIDによって達成しようとしているかわからないんだけど、次のテクニックを使用します。

Merge Into ORAHANCROSSES C 
Using (With D as (select T.*, ROWNUM RN from (select MI_PRINX, GEOLOC from ORAHAN order by MI_PRINX) T) 
     Select aROW.MI_PRINX aROW_MI_PRIX, 
       aROW.GEOLOC aROW_GEOLOC, 
       bROW.MI_PRINX bROW_MI_PRIX, 
       bROW.GEOLOC bROW_GEOLOC, 
       SDO_GEOM.RELATE(aRow.geoloc,'anyinteract', bRow.Geoloc,0.02) RES 
     From D aROW, 
       D bROW 
     Where aROW.RN < bROW.RN 
     ) Q 
On (C.MI_PRIX1 = Q.aROW_MI_PRIX 
    and C.MI_PRIX2 = Q.bROW_MI_PRIX) 
When Matched Then 
    Delete Where Q.RES = 'FALSE' 
When Not Matched Then 
    Insert Values (Q.aROW_MI_PRIX, Q.bROW_MI_PRIX) 
    Where Q.RES = 'TRUE' 
; 

クエリに時間がかかりすぎる場合は、select * from v$session_longops where seconds_remaining >0を入力していつ終了するかを調べることができます。

+0

すべての行を1つずつ外側のループでループする必要があります。しかし、内側のループでは、私は、さらに行をチェックする必要があります(外側のrow.IDよりも大きい)。私はrownumを使っていると思いますか?更新ステートメントはマージステートメントで機能しますか? –

+0

私は "どこに行こうか

+0

テーブルには約400,000のレコードがあり、実行のために50分待っていますが終了しません。なにか提案を? –

関連する問題