0
create or replace procedure Proc_1(P_IN_TABLE_NAME VARCHAR2)
AS
CURSOR T_FACT
IS
SELECT T_ID,T_VER,D_T_ID
from O_T_FACT
where  T_ID is not null
and T_VER is not null;

TYPE call_tab IS TABLE OF O_T_FACT%rowtype;

BEGIN
   IF P_IN_TABLE_NAME ='G_FACT' THEN

   OPEN T_FACT;  
   LOOP 

      EXIT WHEN T_FACT%NOTFOUND ;   

            FETCH T_FACT BULK COLLECT INTO call_data_rec LIMIT no_of_rec;                   
            EXIT WHEN call_data_rec.count = 0;

                       FOR j IN 1..call_data_rec.COUNT
                        loop
                        UPDATE  G_FACT GL set
                        GL.T_ID = call_data_rec(j).T_ID, 
                        GL.T_VER =call_data_rec(j).T_VER,
                        GL.TRANS_FLAG='Y'
                        WHERE GL.G_T_ID = call_data_rec(j).D_T_ID
                        AND GL.T_ID IS NULL 
                        AND GL.T_VER IS NULL;             

                        rec_count := rec_count + 1;                       
                        if mod(rec_count,10000) = 0 then
                        commit;
                        end if;               
                        end loop; 

   end loop;
   CLOSE T_FACT;
   END IF;
End;

この特定の手順には時間がかかります。これを記述する他の方法はありますか? これは単一の更新ステートメントで実行できますか?

以下に示唆されているように、PLS-00436: 実装制限: レコードの BULK In-BIND テーブルのフィールドを参照できません。

For all を使用した新しいコード

create or replace procedure Proc_update_T_ID(P_IN_TABLE_NAME VARCHAR2)
AS
no_of_rec number := 1000;
CURSOR T_and_V_FACT
IS
SELECT O_T_FACT.T_ID, O_T_FACT.T_VER, O_T_FACT.Downstream_T_ID, G_FACT.rowid row_id,
From O_T_FACT, G_FACT
WHERE O_T_FACT.T_ID IS NOT NULL AND G_FACT.G_T_ID = O_T_FACT.Downstream_T_ID
AND T_VER is not null
AND G_FACT.T_VER IS NULL;

TYPE call_tab IS TABLE OF T_and_V_FACT%rowtype index by binary_integer;
call_data_rec call_tab;

BEGIN
   IF P_IN_TABLE_NAME ='G_FACT' THEN
        IF T_and_V_FACT%ISOPEN THEN
            CLOSE T_and_V_FACT;
        END IF;    

        open T_and_V_FACT;

        LOOP

            FETCH T_and_V_FACT BULK COLLECT
            INTO call_data_rec LIMIT no_of_rec;

            FORALL j IN call_data_rec.FIRST .. call_data_rec.LAST    
            UPDATE  G_FACT GL set
                        GL.T_ID = call_data_rec(j).T_ID, 
                        GL.T_VER =call_data_rec(j).T_VER,
                        GL.TRANS_FLAG='Y'
            WHERE GL.rowid = call_data_rec(j).row_id;      

            COMMIT;                  
            call_data_rec.DELETE;
        EXIT WHEN T_and_V_FACT%NOTFOUND;      
        END LOOP;

        CLOSE T_and_V_FACT;
   End if;

END Proc_1;
4

2 に答える 2

2

これを次のような単一のステートメントに書き直すことができるように私には思えます。

update G_FACT GL
set    (GL.T_ID, GL.T_VER, GL.TRANS_FLAG) = 
            (select T_ID,T_VER, 'Y'
              from   O_T_FACT F
              where  F.T_ID is not null
              and    F.T_VER is not null
              and    GL.G_T_ID = F.D_T_ID)
where  exists (select null
               from   O_T_FACT F
               where  F.T_ID is not null
               and    F.T_VER is not null
               and    GL.G_T_ID = F.D_T_ID)
and    GL.T_ID is null
and    GL.T_VER is null; 

これが機能しない場合は、forループをforallステートメントに変換することで大幅な利益を得ることができるはずです。

 FORALL j IN 1..call_data_rec.COUNT
    UPDATE  G_FACT GL set
    GL.T_ID = call_data_rec(j).T_ID, 
    GL.T_VER =call_data_rec(j).T_VER,
    GL.TRANS_FLAG='Y'
    WHERE GL.G_T_ID = call_data_rec(j).D_T_ID
    AND GL.T_ID IS NULL 
    AND GL.T_VER IS NULL;    

commitまた、ループでそれが必要かどうかを再考してください。これを含めると:

  • 処理を遅くします
  • ORA-1555に当たる可能性を高めます
  • データに一貫性のない状態を残す可能性があります
于 2013-03-01T08:59:48.537 に答える
1

ループステートメントではなく、 CURSORを変更して UPDATE を押す必要があると思い
ます 。新しい型を定義する必要があります:RowIDLIMITFOR ALL

CREATE TYPE my_rec AS OBJECT
  ( T_ID NUMBER
  , T_VER number
  , row_id UROWID)
  );

Proc_1を使用すると、次のことが可能になります。

create or replace procedure Proc_1(P_IN_TABLE_NAME VARCHAR2)
AS
no_of_rec number := 1000;
CURSOR T_and_V_FACT
IS
SELECT T_FACT.T_ID, T_FACT.T_VER, T_FACT.D_T_ID, G_FACT.rowid row_id,
  From O_T_FACT, G_FACT
 WHERE T_FACT.T_ID IS NOT NULL AND G_FACT.G_T_ID = O_T_FACT.D_T_ID
   AND T_VER is not null
      -- AND G_FACT.T_ID IS NULL -- not requierd
   AND G_FACT.T_VER IS NULL;

TYPE call_tab IS TABLE OF T_and_V_FACT%rowtype index by binary_integer;
call_data_rec call_tab;

BEGIN
   IF P_IN_TABLE_NAME ='G_FACT' THEN
   IF T_and_V_FACT%ISOPEN THEN
      CLOSE T_and_V_FACT;
   END IF;    
   open T_and_V_FACT;

 LOOP
      FETCH T_and_V_FACT BULK COLLECT
        INTO call_data_rec LIMIT no_of_rec;

      FORALL j IN call_data_rec.FIRST .. call_data_rec.LAST    
       UPDATE  G_FACT GL set
                        GL.T_ID = TREAT(call_data_rec(j) AS my_rec).T_ID, 
                        GL.T_VER =TREAT(call_data_rec(j) AS my_rec).T_VER,
                        GL.TRANS_FLAG='Y'
      WHERE GL.rowid = TREAT(call_data_rec(j) AS my_rec).row_id;      

      COMMIT;                  
      call_data_rec.DELETE;
      EXIT WHEN T_and_V_FACT%NOTFOUND;      
    END LOOP;
    CLOSE T_and_V_FACT;
   End if;
  END Proc_1;

@Ben のコメントに基づいて一部を編集しました。また、バージョン 9i および 10g
に基づいていくつかの変更を行いました 。使用の制限は11g で削除されました。
TREAT

于 2013-03-02T10:23:36.510 に答える