2

私の雇用主は、ビジネスケースに関するメタデータをマスターテーブルと約40の詳細テーブルに格納するアプリケーションを使用しています。

現在、これらのテーブルから読み取り、マスターレコードごとにHTML出力のファイルを生成するパッケージを維持しています。

私のパッケージ本体には次のものが含まれています。

type output_text_type is table of varchar(32768);
function fA(mri in master_record_identifier_type)
        return output_text_type
is
cursor cA(if1 master_record_identifier_type.if1%type, ...)
is
select tA.f1, tA.f2, ...
from tA
where tA.if1 = if1
...;
begin -- fA
        ...
        for r in cA(mri.if1, mri.if2, ...) loop
           <generate HTML using r.f1, r.rf2, mri.if1...>
        end loop;
end fA;
... some 40 more function with the same structure ...

ところで、ほとんどのカーソルは100レコード未満(ほとんどの場合0または1)をfetch ... bulk collect ...返すため、パフォーマンスは向上しません。

今、私たちはビジネスケースのメタデータ(そしてもちろん、ドキュメント自体)を他の組織と交換することを計画しています。このためには、実質的に同じ内容のxmlデータ構造を生成する必要があります。

この要件を満たすために、現在のパッケージ(model-view-controllerパターンのアイデアに影響されます)をパッケージpkg_cursors、pkg_html、および(まだ作成されていない)pkg_xmlに分割する予定です。

残念ながら、レコードを次のように定義することで、実用的な解決策しか見つかりませんでした。

create or replace package pkg_cursors
as
type rA is record(
       if1 tA.if1%type,
       f1  tA.f1%type, 
       f2  tA.f2%type,
       ... a dozen more fields ...
       );
cursor ca(master_record_identifier_type.if1%type, ...)
     return rA;
...

これは残念なことです。これまで、テーブルに列を追加すると、カーソルのselect句が更新され、新しい列がcursor-for-loopに追加されていました。これから、考慮すべき3番目の場所があります。それはレコード定義です。

パッケージ仕様のカーソルも試してみました。

create package pkg_cursors
as
cursor cA(...) is
select <select-list>
from ... where ...
return cA%rowtype;

しかし、コンパイルエラーが発生しました。

したがって、私の質問は次のとおりです。カーソル戻り引数のレコード定義を回避する方法はありますか?

パッケージを分割するより良い方法があると思いますか?

(私の言語の誤りとこの質問の長さをお詫びしてください。私の英語のコマンドがもっとしっかりしていれば、この質問はおそらくもっと短くなるでしょう。)

4

1 に答える 1

1

問題に役立つ場合は、動的SQLサンプルですか?もちろん、パイプライン化する必要はありません。私はそのようにしただけです。

SQL> create table one (id number, foo varchar2(20), if1 number);

Table created.

SQL> create table two (id number, foo varchar2(20), foo2 date, if1 number);

Table created.

SQL> insert into one values(1, 'test', 1);

1 row created.

SQL> insert into one values(1, 'test again', 1);

1 row created.

SQL> insert into two values(1, '2nd table', sysdate-1, 1);

1 row created.

SQL> insert into two values(1, '2nd table - 2', sysdate-10, 1);

1 row created.

SQL> insert into two values(1, '2nd table - 3', sysdate-3, 1);

1 row created.

SQL> create type vc_tab as table of varchar2(4000);
  2  /

Type created.

SQL> create or replace function gen_html(p_tab in varchar2, p_master_id in number)
  2  return vc_tab
  3  pipelined
  4  is
  5    v_cur           integer default dbms_sql.open_cursor;
  6    v_col_val       varchar2(4000);
  7    v_col_val_clob  clob;
  8    v_status        integer;
  9    v_desc_tbl      dbms_sql.desc_tab;
 10    v_col_cnt       number;
 11    v_row           varchar2(4000);
 12  begin
 13    execute immediate 'alter session set nls_date_format=''dd-mon-yyyy hh24:mi:ss'' ';
 14    execute immediate 'alter session set nls_timestamp_tz_format=''dd-mon-yyyy hh24:mi:ssxff tzh:tzm''';
 15    execute immediate 'alter session set nls_timestamp_format=''dd-mon-yyyy hh24:mi:ssxff''';
 16
 17    dbms_sql.parse(v_cur,  'select * from ' || dbms_assert.simple_sql_name(p_tab) || ' where if1 = :b1',
 18                   dbms_sql.native);
 19    dbms_sql.bind_variable(v_cur, 'b1', p_master_id);
 20    dbms_sql.describe_columns(v_cur, v_col_cnt, v_desc_tbl);
 21
 22    for i in 1 .. v_col_cnt
 23    loop
 24      if (v_desc_tbl(i).col_type = 109)
 25      then
 26        dbms_sql.define_column(v_cur, i, v_col_val_clob);
 27      else
 28        dbms_sql.define_column(v_cur, i, v_col_val, 4000);
 29      end if;
 30    end loop;
 31
 32    v_status := dbms_sql.execute(v_cur);
 33
 34    pipe row('<h1>' || p_tab || '</h1>');
 35    pipe row('<table>');
 36    while ( dbms_sql.fetch_rows(v_cur) > 0 )
 37    loop
 38      pipe row('<tr>');
 39      for i in 1 .. v_col_cnt
 40      loop
 41        if (v_desc_tbl(i).col_type = 109)
 42        then
 43          dbms_sql.column_value(v_cur, i, v_col_val_clob);
 44          pipe row('<td>' || v_desc_tbl(i).col_name || '</td><td>' || v_col_val_clob || '</td>');
 45        else
 46          dbms_sql.column_value(v_cur, i, v_col_val);
 47          pipe row('<td>' || v_desc_tbl(i).col_name || '</td><td>' || v_col_val || '</td>');
 48        end if;
 49      end loop;
 50      pipe row('</tr>');
 51    end loop;
 52    pipe row('</table>');
 53    dbms_sql.close_cursor(v_cur);
 54
 55  end;
 56  /

Function created.

SQL> select * from table(gen_html('ONE', 1));

COLUMN_VALUE
--------------------------------------------------------------------------------
<h1>ONE</h1>
<table>
<tr>
<td>ID</td><td>1</td>
<td>FOO</td><td>test</td>
<td>IF1</td><td>1</td>
</tr>
<tr>
<td>ID</td><td>1</td>
<td>FOO</td><td>test again</td>
<td>IF1</td><td>1</td>
</tr>
</table>

13 rows selected.

SQL> select * from table(gen_html('TWO', 1));

COLUMN_VALUE
--------------------------------------------------------------------------------
<h1>TWO</h1>
<table>
<tr>
<td>ID</td><td>1</td>
<td>FOO</td><td>2nd table</td>
<td>FOO2</td><td>08-nov-2012 18:37:36</td>
<td>IF1</td><td>1</td>
</tr>
<tr>
<td>ID</td><td>1</td>
<td>FOO</td><td>2nd table - 2</td>
<td>FOO2</td><td>30-oct-2012 18:37:36</td>
<td>IF1</td><td>1</td>
</tr>
<tr>
<td>ID</td><td>1</td>
<td>FOO</td><td>2nd table - 3</td>
<td>FOO2</td><td>06-nov-2012 18:37:36</td>
<td>IF1</td><td>1</td>
</tr>
</table>

21 rows selected.
于 2012-11-09T18:40:15.937 に答える