【问题标题】:How to eliminate subtype dependency?如何消除子类型依赖?
【发布时间】:2011-10-06 00:27:01
【问题描述】:

在下面的示例中,我为每个pls_integer 子类型编写了一个to_str() 函数和一个set() 过程。除了类型之外,功能和过程几乎相同。

如何在不放弃子类型提供的约束的情况下消除为新子类型编写另一个 to_str() 和 set() 的需要?

回退到varchar2 喜欢

procedure set(list in varchar2, prefix in varchar2)

然后将其称为

set(to_str(list), 'foos:')

听起来不太好,我仍然需要为每个子类型提供to_str()。

我是 Oracle 新手,我愿意接受各种不同的建议,几乎每天都有新的 Oracle 功能让我大吃一惊。

我正在运行 11.2.0.1.0。

create table so1table (
  id number,
  data varchar(20)
);

create or replace package so1 as
  subtype foo_t is pls_integer range 0 .. 4 not null;
  type foolist is table of foo_t;
  procedure set(id_ in number, list in foolist default foolist(1));

  subtype bar_t is pls_integer range 5 .. 10 not null;
  type barlist is table of bar_t;
  procedure set(id_ in number, list in barlist default barlist(5));
end;
/
show errors

create or replace package body so1 as
  /* Do I have always to implement these very similar functions/procedures for
  every single type ? */
  function to_str(list in foolist) return varchar2 as
    str varchar2(32767);
  begin
    for i in list.first .. list.last loop
      str := str || ' ' || list(i);
    end loop;
    return str;
  end;

  function to_str(list in barlist) return varchar2 as
    str varchar2(32767);
  begin
    for i in list.first .. list.last loop
      str := str || ' ' || list(i);
    end loop;
    return str;
  end;

  procedure set(id_ in number, list in foolist default foolist(1)) as
    values_ constant varchar2(32767) := 'foos:' || to_str(list);
  begin
    insert into so1table (id, data) values (id_, values_);
  end;

  procedure set(id_ in number, list in barlist default barlist(5)) as
    values_ constant varchar2(32767) := 'bars:' || to_str(list);
  begin
    insert into so1table (id, data) values (id_, values_);
  end;
end;
/
show errors

begin
  so1.set(1, so1.foolist(0, 3));
  so1.set(2, so1.barlist(5, 7, 10));
end;
/

SQLPLUS> select * from so1table;

        ID DATA
---------- --------------------
         1 foos: 0 3
         2 bars: 5 7 10

【问题讨论】:

  • 基于到目前为止的响应(18 个赞成票、4 个最爱和两个不太精确的答案),我认为这是 PL/SQL 的痛点,而子类型可能不可能。也许我必须使用更大的锤子:Using PL/SQL With Object Types?

标签: oracle plsql oracle11g oracle11gr2 subtype


【解决方案1】:
create table so1table (
    id number,
    data varchar(20)
);


create or replace type parent_type as object
(
    v_number number,
    --Prefix probably belongs with a list, not an individual value.
    --For simplicity, I'm not adding another level to the objects.
    v_prefix varchar2(10)
) not instantiable not final;
/

create or replace type parentlist as table of parent_type;
/


create or replace type foo_type under parent_type
(
    constructor function foo_type(v_number number) return self as result
);
/

--The data must be stored as a NUMBER, since ADTs don't support
--PL/SQL specific data types.  The type safety is enforced by the
--conversion in the constructor.
create or replace type body foo_type is
    constructor function foo_type(v_number number) return self as result
    as
        subtype foo_subtype is pls_integer range 0 .. 4 not null;
        new_number foo_subtype := v_number;
    begin
        self.v_number := new_number;
        self.v_prefix := 'foos:';
        return;
    end;
end;
/

create or replace type foolist as table of foo_type;
/


create or replace type bar_type under parent_type
(
    constructor function bar_type(v_number number) return self as result
);
/

create or replace type body bar_type is
    constructor function bar_type(v_number number) return self as result
    as
        subtype bar_subtype is pls_integer range 5 .. 10 not null;
        new_number bar_subtype := v_number;
    begin
        self.v_number := new_number;
        self.v_prefix := 'bars:';
        return;
    end;
end;
/

create or replace type barlist as table of bar_type;
/



create or replace package so1 as
    procedure set(id_ in number, list in parentlist);
end;
/

create or replace package body so1 as

    function to_str(list in parentlist) return varchar2 as
        v_value VARCHAR2(32767);
    begin
        for i in list.first .. list.last loop
            if i = 1 then
                v_value := list(i).v_prefix;
            end if;
            v_value := v_value || ' ' || list(i).v_number;
        end loop;

        return v_value;
    end to_str;

    procedure set(id_ in number, list in parentlist) as
        values_ constant varchar2(32767) := to_str(list);
    begin
        insert into so1table (id, data) values (id_, values_);
    end set;
end so1;
/


begin
    --You probably don't want to mix foos and bars, but it is allowed. 
    so1.set(1, parentlist(foo_type(0), foo_type(3)));
    so1.set(2, parentlist(bar_type(5), bar_type(7), bar_type(10)));

    --These would generate "ORA-06502: PL/SQL: numeric or value error"
    --so1.set(1, parentlist(foo_type(5)));
    --so1.set(1, parentlist(bar_type(4)));

end;
/

select * from so1table;

【讨论】:

  • 终于找到了一个有意义的答案。谢谢 !目前我不喜欢所有这些对象类型都不能隐藏在包中,而是污染用户的命名空间。我想这就是 Oracle 的方式。
【解决方案2】:

以下答案实际上是关于你如何在 postgresql(和 plpgsql)中做到这一点,我也不知道 oracle 子类型,但我认为它们足够相似,至少它会引导你到你的回答。

create function add (anynonarray,anynonarray) returning anynonarray
as 'begin return $1 + $2; end';

我知道我搞砸了语法,但无论如何它应该显示我想要显示的内容。

这个想法是它将“anynonarray”or any of the alternatives 替换为调用参数的类型。一个限制是上面示例中的所有“anynonarray”都将属于同一类型。

文档将此称为多态性。

【讨论】:

    【解决方案3】:

    这可能无法回答您的问题,但为什么不将数据放在常规表中,然后使用 wm_concat 聚合函数将它们连接起来?

    即,

    > select * from myTable;
    
    ID  Category  Value
    --- --------- ------
    1   foo       0
    2   foo       3
    3   bar       5
    4   bar       7
    5   bar       10
    
    > select   Category||'s: '||replace(wm_concat(Value),',',' ') Data
      from     myTable
      group by Category;
    
    Data
    -------------
    bars: 5 7 10
    foos: 0 3
    

    wm_concat 与类型无关,因此无需重载函数。而且,还有其他methods可以使用;解析函数的方法看起来不错,但是我没有11g可以测试!

    (编辑否则,我认为您可以使用 Oracle 的对象模型实现您正在寻找的东西;特别是多态性。但是,这超出了我的范围......所以也许其他人可以插话。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-09-28
      • 2016-06-03
      • 2013-12-10
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 2019-07-27
      相关资源
      最近更新 更多