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 条记录(通常为零或一条),因此fetch ... bulk collect ...不会导致性能提升。

现在我们计划与其他组织交换业务案例的元数据(当然还有文档本身)。为此,我们必须生成具有 - 实质上 - 相同内容的 xml 数据结构。

为了满足这个要求,我计划将我当前的包(受模型-视图-控制器模式的影响)拆分为一个包 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 子句并将新列添加到游标循环中。从现在开始,我要考虑第三个地方:记录定义。

我还尝试了包规范中的游标:

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 回答