0

問題:

外部ソースからの固定長レコードである CLOB を含むテーブルがあります。1 ~ 5 の位置 = フィールド A、6 ~ 12 の位置 = フィールド B など。

そのレコード レイアウトを定義する別のテーブル (LayoutDefinition) があります。

FieldName = 'fieldA'
FieldStart = 1
FieldLength = 5
FieldName = 'fieldB'
FieldStart = 6
FieldLength = 6

CLOB からデータを取得し、それを「tableA_rec tableA%rowtype」などの %rowtype 変数に入れる必要があります。

大規模な case ステートメントを使用するルーチンを実装しました。LayoutDefiniton テーブルの各行のループは、CLOB の領域を tablea_rec のような適切な変数に移動します。

CASE LayoutDefiniton.FieldName
WHEN 'fieldA' THEN tablea_rec.fieldA:= SUBSTR(inputClob,LayoutDefiniton.FieldStart,LayoutDefiniton.FieldLength);
WHEN 'fieldB' THEN tablea_rec.fieldB:= SUBSTR(inputClob,LayoutDefiniton.FieldStart,LayoutDefiniton.FieldLength);

もちろん、これは非常に非効率的です。データを分解するレコードごとにレイアウトをループする必要があるからです。

私がやりたいことは、テーブルから適切な変数にデータを取得する動的SQL選択ステートメントを一度作成することです。たとえば、動的でない場合は次のようになります。

select substr(inputCLOB,1,5), substr(inputCLOB,6,6) into FieldA, fieldB from CLOBTable;

これは動的 SQL を使用して実行できますか?

もしそうなら、構文はどのようになりますか?

4

1 に答える 1

1

次のコードは、CLOB 列からデータを抽出し、宛先テーブルに挿入します。

DECLARE
  l_sql_str VARCHAR2(4000);
BEGIN
  WITH src_meta_agg AS(
    SELECT LISTAGG(field_name, ',') WITHIN GROUP(ORDER BY field_start) AS field_list
           ,LISTAGG('substr(lob,' || field_start || ', ' || field_length || ')', ',') WITHIN GROUP( ORDER BY field_start) AS field_source
      FROM src_meta)
    SELECT 'INSERT INTO dest(' || field_list || ') SELECT ' || field_source ||
           ' FROM src' INTO l_sql_str
      FROM src_meta_agg;

  EXECUTE IMMEDIATE l_sql_str;
END;

LISTAGGデータを並べ替えて値を連結する11gの関数です。以前のバージョンでは、wm_concatまたは他のアプローチを使用できます。次l_sql_strのステートメントがあります。

INSERT INTO dest(field1,field2) SELECT substr(lob,1, 5),substr(lob,6, 6) FROM src

PL/SQL でデータを処理する必要がある場合は、このコードでうまくいきます

DECLARE
  l_sql_str VARCHAR2(4000);
  TYPE t_dest_tbl IS TABLE OF dest%ROWTYPE;
  l_dest_rows t_dest_tbl;
  l_cursor SYS_REFCURSOR;
BEGIN

  WITH src_meta_agg AS(
    SELECT LISTAGG(field_name, ',') WITHIN GROUP(ORDER BY field_start) AS field_list
           ,LISTAGG('substr(lob,' || field_start || ', ' || field_length || ')', ',') WITHIN GROUP( ORDER BY field_start) AS field_source
      FROM src_meta)
    SELECT 'SELECT ' || field_source ||
           ' FROM src' INTO l_sql_str
      FROM src_meta_agg;

  OPEN l_cursor FOR l_sql_str;
  FETCH l_cursor
  BULK COLLECT INTO l_dest_rows;
  CLOSE l_cursor; 

  FOR i IN 1..l_dest_rows.COUNT LOOP
    dbms_output.put_line(l_dest_rows(i).field1 || ', ' || l_dest_rows(i).field2);
  END LOOP;
END;

これが私が使用したスキーマです

create table src(lob clob)
/
insert into src values ('12345ABCDEF')
/
insert into src values ('78901GHIJKL')
/

create table src_meta(field_name varchar2(100), field_start number, field_length number)
/

insert into src_meta values ('field1', 1, 5)
/
insert into src_meta values ('field2', 6, 6)
/

create table dest(field1 varchar2(5), field2 varchar2(6))
/
于 2013-08-26T16:47:45.607 に答える