ODCITable实现无法正确调用ODCITablePrepare

时间:2018-08-21 12:51:56

标签: sql oracle plsql

主要思想是,我想在不事先了解列的情况下实现透视功能。我找到了该here的脚本,但它只用于一列,我想旋转两列。

与使用 PivotImpl 返回流水线结果相比,我具有功能 Pivot

create or replace function Pivot(p_stmt                  in varchar2,
                     p_aggr_function         in varchar2 := 'max')
    return anydataset
    pipelined using PivotImpl;

类型 PivotImpl 是ODCITable(更多here)的实现。

CREATE OR REPLACE TYPE PivotImpl as object
(
  ret_type anytype, -- The return type of the table function
  stmt     varchar2(32767),

  aggr_function         varchar2(32767),
  cur                   integer,

  static function ODCITableDescribe(rtype                   out anytype,
                                    p_stmt                  in varchar2)
    return number,

  static function ODCITablePrepare(sctx                    out PivotImpl,
                                   ti                      in sys.ODCITabFuncInfo,
                                   p_stmt                  in varchar2,
                                   p_aggr_function         in varchar2 := 'max')
    return number,

  static function ODCITableStart(sctx                    in out PivotImpl,
                                 p_stmt                  in varchar2)
    return number,

  member function ODCITableFetch(self   in out PivotImpl,
                                 nrows  in number,
                                 outset out anydataset) return number,

  member function ODCITableClose(self in PivotImpl) return number
)

我的 ODCITablePrepare 如下:

static function ODCITablePrepare(sctx                    out PivotImpl,
                                   ti                      in sys.ODCITabFuncInfo,
                                   p_stmt                  in varchar2,
                                   p_aggr_function         in varchar2 := 'max')
    return number is
    prec     pls_integer;
    scale    pls_integer;
    len      pls_integer;
    csid     pls_integer;
    csfrm    pls_integer;
    elem_typ anytype;
    aname    varchar2(30);
    tc       pls_integer;
  begin
    tc := ti.RetType.GetAttrElemInfo(1,
                                     prec,
                                     scale,
                                     len,
                                     csid,
                                     csfrm,
                                     elem_typ,
                                     aname);
    --
    dbms_output.put_line('Prepare: ' || p_stmt); -- !!!HERE IS MY DEBUG FOR p_stmt VALUES
      sctx := PivotImpl(elem_typ,
                         p_stmp,
                         p_aggr_function,
                         null);

    return odciconst.success;
  end;

在ODCITableClose中,我每次都会使类型无效,并且每次都将强制调用ODCITablePrepare,然后执行我的SELECT。

ODCITableClose 函数的实现是:

  member function ODCITableClose(self in PivotImpl) return number is
    c    integer;
    t_id number;
  begin
    c := self.cur;
    dbms_sql.close_cursor(c);
    select object_id
      into t_id
      from user_objects
      where object_name = $$PLSQL_UNIT -- name of your type!
      and object_type = 'TYPE BODY';
 -- invalidating of the type body forces that ODCITableDescribe is executed for every call to the pivot function
 -- and we do need that to make sure that any new columns are picked up (= new values for the pivoting column)
      dbms_utility.invalidate( t_id );
    return odciconst.success;
  end;

我有两个选择几乎相等的SELECT,它们的工作原理不同。 在输出的第一个SELECT中,我可以看到 p_stmt 的值为空(来自ODCITablePrepare中的调试)。首先选择:

select *
  from table(Pivot(p_stmt => 'select account_number, branch_code, field_name, field_value,field_value_descr
                    from account_map
                    group by account_number,branch_code, field_name,field_value,field_value_descr'))
;

在第二种情况下,我使用视图:

create or replace view v_account_map as
select *
  from table(Pivot('select account_number, branch_code, field_name, field_value,field_value_descr
                    from account_map
                    group by account_number,branch_code, field_name,field_value,field_value_descr'))
;

然后选择:

select *
from v_account_map t

p_stmt的第二个选择值是我传递给Pivot函数的值。

我无法理解的另一个奇怪的想法是为什么在打开 v_account_map 实现我的

  

选择*

替换为真实的列名

  

选择“ ACCOUNT_NUMBER”,“ BRANCH_CODE”,“ A1”,“ A2”,“ A3”

当我添加过滤器以从必须返回结果的视图中进行选择时,结果为空。示例:

select *
  from table(Pivot(p_stmt => 'select account_number, branch_code, field_name, field_value,field_value_descr
                    from account_map 
                    group by account_number,branch_code, field_name,field_value,field_value_descr'))
where account_number = '42342325345452'; --> RETURN 1 row
;

select *
from V_ACCOUNT_MAP t
where account_number = '42342325345452'; --> RETURN 0 rows

在没有过滤器的情况下,两个选择会返回相同的结果。

我的第一个问题是,为什么在第一种情况下ODCITablePrepare不被称为corect,而在第二种情况下称为corect?

第二个问题是为什么我在从ODCITable过滤结果时遇到问题?实际上,问题不仅在于过滤。分组依据也很奇怪。例如,结果必须为 10,20,30,40 。第一次选择结果为 40,40,40,40 ,第二次选择(从视图中)结果仅为 40

也许我在实现过程中遗漏了一些东西,但是我可以看到它是什么。

其他信息: 我不确定是不是我的Oracle版本,但是:

OCI: version 11.1
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 

0 个答案:

没有答案