Oracle 如何消除子类型依赖关系?
在下面的示例中,我为每个Oracle 如何消除子类型依赖关系?,oracle,plsql,oracle11g,oracle11gr2,subtype,Oracle,Plsql,Oracle11g,Oracle11gr2,Subtype,在下面的示例中,我为每个pls\u integer子类型编写了一个到str()函数和一个set()过程。除类型外,功能和程序几乎相同 如何在不放弃子类型提供的约束的情况下,消除为新子类型编写另一个到_str()和set()的需要 回到varchar2like procedure set(list in varchar2, prefix in varchar2) 然后称之为 set(to_str(list), 'foos:') 这听起来不是个好主意,我仍然需要为每个子类型提供to_str()
pls\u integer
子类型编写了一个到str()
函数和一个set()
过程。除类型外,功能和程序几乎相同
如何在不放弃子类型提供的约束的情况下,消除为新子类型编写另一个到_str()
和set()
的需要
回到varchar2
like
procedure set(list in varchar2, prefix in varchar2)
然后称之为
set(to_str(list), 'foos:')
这听起来不是个好主意,我仍然需要为每个子类型提供to_str()
我是甲骨文的新手,对各种各样的建议都持开放态度,甲骨文的新功能几乎每天都让我大吃一惊
我正在运行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
这可能无法回答您的问题,但为什么不将数据放在一个常规表中,然后使用
wm_concat
聚合函数将它们连接起来呢
i、 e
wm_concat
与类型无关,因此您无需重载函数。此外,还有其他可以使用的方法;解析函数法看起来不错,但我没有11g测试
(编辑否则,我认为你可以使用Oracle的对象模型实现你想要的目标;特别是多态性。然而,这是我无法理解的…所以也许其他人可以插话。)以下答案实际上是关于你在postgresql(和plpgsql)中如何实现的,我也不知道Oracle的子类型,但我认为它们非常相似,至少会引导你找到答案
create function add (anynonarray,anynonarray) returning anynonarray
as 'begin return $1 + $2; end';
我知道我把语法弄糟了,但无论如何,它应该显示我想用它显示的东西
其思想是,它将用调用的参数类型替换“anynonarray”。一个限制是上面示例中的所有“anynonarray”都是相同的类型
文档将此称为多态性。根据回答(18张赞成票,4张赞成票和两个不太准确的答案),到目前为止,我认为这是PL/SQL的痛点,子类型可能不可能。也许我得用一把更大的锤子:?终于有了一个有意义的答案。谢谢目前,我不喜欢所有这些对象类型都不能隐藏在包中,而是污染用户的名称空间。我想甲骨文就是这样。
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;
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;