Oracle:在不知道列类型的情况下管道查询结果

时间:2016-01-07 21:20:38

标签: oracle plsql

我知道这是可能的:

SQL> create or replace type tp_asset as object (assetId number, asset_name varchar2(100), asset_val number)
  2  /
Type created
SQL> create or replace type tp_tab_asset is table of tp_asset;
  2  /
Type created
SQL> create or replace function fnc_AssetAttributeByType(p_num in number) return tp_tab_asset pipelined as
  2    v_tp_asset tp_asset;
  3  begin
  4    for i in 1 .. 3
  5      loop
  6      v_tp_asset := tp_asset(i, 'ABC', i * 3);
  7      pipe row (v_tp_asset);
  8    end loop;
  9    return;
 10  end;
 11  /
Function created

但这看起来非常愚蠢。为什么我要在两个位置维护列的列表?我正在将T-SQL翻译成Oracle,我想做以下事情:

create or replace 
FUNCTION fnc_AssetAttributeByType(
    p_ATTRIBUTETYPEID IN NUMBER)
  RETURN ******TABLE???????? pipelined
AS
BEGIN
  FOR j IN
  (
    SELECT
      a.AssetID,
      ShortName,
      LongName,
      ATTRIBUTEVALUE
    FROM
      DBO$ASSET A
    INNER JOIN dbo$asset_attribute aa
    ON
      A.ASSETID = AA.ASSETID
    INNER JOIN dbo$attribute att
    ON
      AA.ATTRIBUTEID = ATT.ATTRIBUTEID
    WHERE
      ATTRIBUTETYPEID = p_ATTRIBUTETYPEID
  )
  LOOP
    pipe row (j);
  END LOOP;
  RETURN;
END;

告诉我,我是否理智,或者这不是Oracle超级说法的方式

2 个答案:

答案 0 :(得分:0)

我可以考虑在包中声明一个类型,我可以通过使用视图的%rowtype列来实现它(从@Justin Cave借用)。

SQL> col shortname format a20
SQL> col longname format a20
SQL> drop table dbo$asset;
Table dropped
SQL> drop table dbo$asset_attribute;
Table dropped
SQL> drop table dbo$attribute;
Table dropped
SQL> create table dbo$asset (assetid number);
Table created
SQL> create table dbo$asset_attribute (attributeid number, assetid number, shortname varchar2(100), longname varchar2(100));
Table created
SQL> create table dbo$attribute (attributeid number, assetid number, attributevalue number, attributetypeid number);
Table created
SQL> insert into dbo$asset values (1);
1 row inserted
SQL> insert into dbo$asset_attribute values (10, 1, 'ATT1', 'ATTRIBUTE1');
1 row inserted
SQL> insert into dbo$asset_attribute values (20, 1, 'ATT2', 'ATTRIBUTE2');
1 row inserted
SQL> insert into dbo$attribute values (10, 1, 999.99, 444);
1 row inserted
SQL> insert into dbo$asset values (2);
1 row inserted
SQL> insert into dbo$asset_attribute values (30, 2, 'ATT1', 'ATTRIBUTE1');
1 row inserted
SQL> insert into dbo$asset_attribute values (40, 2, 'ATT2', 'ATTRIBUTE2');
1 row inserted
SQL> insert into dbo$attribute values (40, 2, 888.99, 555);
1 row inserted
SQL> create or replace view vw_assetattributebytype as
  2  SELECT a.assetid, shortname, longname, attributevalue, attributetypeid
  3    FROM dbo$asset a
  4    JOIN dbo$asset_attribute aa ON a.assetid = aa.assetid
  5    JOIN dbo$attribute att ON aa.attributeid = att.attributeid;
View created
SQL> create or replace package pck_asset is
  2    type tp_assetattributebytype is table of vw_assetattributebytype%rowtype;
  3  
  4    function fnc_assetattributebytype(p_attributetypeid in number) return tp_assetattributebytype pipelined;
  5  end pck_asset;
  6  /
Package created
SQL> create or replace package body pck_asset is
  2  
  3    function fnc_assetattributebytype(p_attributetypeid in number) return tp_assetattributebytype pipelined is
  4    begin
  5      for j in (select *
  6                  from vw_assetattributebytype
  7                 where attributetypeid = p_attributetypeid)
  8      loop
  9        pipe row(j);
 10      end loop;
 11    end fnc_assetattributebytype;
 12  
 13  end pck_asset;
 14  /
Package body created
SQL> select *
  2    from table(pck_asset.fnc_assetattributebytype(444));
   ASSETID SHORTNAME            LONGNAME             ATTRIBUTEVALUE ATTRIBUTETYPEID
---------- -------------------- -------------------- -------------- ---------------
         1 ATT1                 ATTRIBUTE1                   999,99             444

SQL> 

问题是你需要在我的例子中将过滤器列ATTRIBUTETYPEID添加到视图中。有解决它的方法,即使使用应用程序上下文在视图内部进行过滤,它也相当简单。如果您必须仅使用查询中最初的列来保持视图,则可以执行此操作而不是:

SQL> col shortname format a20
SQL> col longname format a20
SQL> drop table dbo$asset;
Table dropped
SQL> drop table dbo$asset_attribute;
Table dropped
SQL> drop table dbo$attribute;
Table dropped
SQL> create table dbo$asset (assetid number);
Table created
SQL> create table dbo$asset_attribute (attributeid number, assetid number, shortname varchar2(100), longname varchar2(100));
Table created
SQL> create table dbo$attribute (attributeid number, assetid number, attributevalue number, attributetypeid number);
Table created
SQL> insert into dbo$asset values (1);
1 row inserted
SQL> insert into dbo$asset_attribute values (10, 1, 'ATT1', 'ATTRIBUTE1');
1 row inserted
SQL> insert into dbo$asset_attribute values (20, 1, 'ATT2', 'ATTRIBUTE2');
1 row inserted
SQL> insert into dbo$attribute values (10, 1, 999.99, 444);
1 row inserted
SQL> insert into dbo$asset values (2);
1 row inserted
SQL> insert into dbo$asset_attribute values (30, 2, 'ATT1', 'ATTRIBUTE1');
1 row inserted
SQL> insert into dbo$asset_attribute values (40, 2, 'ATT2', 'ATTRIBUTE2');
1 row inserted
SQL> insert into dbo$attribute values (40, 2, 888.99, 555);
1 row inserted
SQL> create or replace context ctx_asset using pck_asset;
Context created
SQL> create or replace view vw_assetattributebytype as
  2  SELECT a.assetid, shortname, longname, attributevalue
  3    FROM dbo$asset a
  4    JOIN dbo$asset_attribute aa ON a.assetid = aa.assetid
  5    JOIN dbo$attribute att ON aa.attributeid = att.attributeid
  6   WHERE attributetypeid = sys_context('ctx_asset', 'attributetypeid');
View created
SQL> create or replace package pck_asset is
  2    type tp_assetattributebytype is table of vw_assetattributebytype%rowtype;
  3  
  4    function fnc_assetattributebytype(p_attributetypeid in number) return tp_assetattributebytype pipelined;
  5    procedure prc_set_attributetype(p_attributetypeid in number);
  6  
  7  end pck_asset;
  8  /
Package created
SQL> create or replace package body pck_asset is
  2  
  3    procedure prc_set_attributetype(p_attributetypeid in number) is
  4    begin
  5      dbms_session.set_context('ctx_asset', 'attributetypeid', p_attributetypeid);
  6    end;
  7  
  8    function fnc_assetattributebytype(p_attributetypeid in number) return tp_assetattributebytype pipelined is
  9    begin
 10      -- sets the filter on the application context for the view
 11      prc_set_attributetype(p_attributetypeid);
 12  
 13      for j in (select *
 14                  from vw_assetattributebytype)
 15      loop
 16        pipe row(j);
 17      end loop;
 18    end fnc_assetattributebytype;
 19  
 20  end pck_asset;
 21  /
Package body created
SQL> select *
  2    from table(pck_asset.fnc_assetattributebytype(555));
   ASSETID SHORTNAME            LONGNAME             ATTRIBUTEVALUE
---------- -------------------- -------------------- --------------
         2 ATT2                 ATTRIBUTE2                   888,99

SQL> 

我对你的桌子结构做了很多假设,他们可能不正确,原谅我任何错误。想法是展示一个运行的示例代码。

答案 1 :(得分:0)

可以使用ANYDATASET和Oracle Data Cartridge创建一个返回未知列类型结果的Oracle函数。

我见过的唯一一个实现是Adrian Billington的Dictionary Long Application。该程序用于将LONG列转换为CLOB,以便更轻松地查询数据字典。通过删除LONG和CLOB代码,它将成为更通用的动态查询引擎。

虽然这是一个很棒的程序,但我通常建议不要使用它。有许多错误和限制。 ANY *类型很少使用且充满惊喜。

不幸的是,这主要是一个仅限链接的答案。解决这个看似简单的任务需要数百行拜占庭代码。这也是我建议您找到另一种方法的另一个原因,即使这意味着创建额外的TYPE。