Oracle では、ソースからターゲットにレコードを挿入し、ターゲットが更新されたらソースの PROCESSED_DATE フィールドを更新する必要があるという要件があります。
1つの方法は、カーソルを使用して行ごとにループし、同じことを達成することです。
効率的な方法で同じことを行う他の方法はありますか?
Oracle では、ソースからターゲットにレコードを挿入し、ターゲットが更新されたらソースの PROCESSED_DATE フィールドを更新する必要があるという要件があります。
1つの方法は、カーソルを使用して行ごとにループし、同じことを達成することです。
効率的な方法で同じことを行う他の方法はありますか?
カーソルは必要ありません。まだ転送されていない行を転送すると仮定します (processed_date の NULL 値で識別されます)。
insert into target_table (col1, col2, col3)
select col1, col2, col3
from source_table
where processed_date is null;
update source_table
set processed_date = current_timestamp
where processed_date is null;
commit;
INSERT の実行時または INSERT と更新の間に挿入された行の更新を避けるには、シリアル化可能モードでトランザクションを開始します。
INSERT を実行する前に、次のステートメントを使用してトランザクションを開始します。
set transaction isolation level SERIALIZABLE;
詳細については、次のマニュアルを参照してください。
他の誰かから別の答えを得ました。すべての新しいレコードのPROCESSED_DATEがnull(レコードがターゲットテーブルに挿入されたときに挿入された30行)になるため、分離レベルを有効にするよりもはるかに合理的であると考えられます。また、PROCESSED_DATE=NULL行は次の方法でのみ更新できます。私の仕事を使っています。他のユーザーは、これらのレコードをいつでも更新できません。
declare
date_stamp date;
begin
select sysdate
into date_stamp
from dual;
update source set processed_date = date_stamp
where procedded_date is null;
Insert into target
select * from source
where processed_date = date_stamp;
commit;
end;
/
これについてさらに考えを教えてください。これについてのすべてのあなたの助けに感謝します。
この種のインスタンスでの私の好ましい解決策は、バッチ DML とともに PL/SQL 配列を使用することです。
DECLARE
CURSOR c IS SELECT * FROM tSource;
TYPE tarrt IS TABLE OF c%ROWTYPE INDEX BY BINARY_INTEGER;
tarr tarrt;
BEGIN
OPEN c;
FETCH c BULK COLLECT INTO tarr;
CLOSE c;
FORALL i IN 1..tarr.COUNT
INSERT INTO tTarget VALUES tarr(i);
FORALL i IN 1..tarr.COUNT
UPDATE tSource SET processed_date = SYSDATE
WHERE tSource.id = tarr(i).id;
END;
上記のコードは単なる例であり、テーブルの構造についていくつかの仮定をしています。
最初にソース テーブルにクエリを実行し、それらのレコードのみを挿入および更新します。つまり、実行中に他のセッションが同時にソース テーブルにさらにレコードを挿入することを心配する必要はありません。
ここにあるように一度に行を処理するのではなく、(fetch LIMIT 句とループを使用して) バッチで行を処理するように簡単に変更することもできます。
トリガーが機能するはずです。ターゲット テーブルには、更新時にソース テーブルの列を処理日で更新するトリガーを設定できます。