1)集合的分类
Oracle支持3种类型的集合:
关联数组(Associative array,即Index-by table)
嵌套表(Nested table)
变长数组(VARRAY)
它们的区别之一是, Nested table与VARRY既可以被用于PL/SQL,也可以被直接用于数据库中,但是Associative array不行,也就是说,Associative array是不能通过CREATE TYPE语句进行单独创建,只能在PL/SQL块(或Package)中进行定义并使用(即适用范围是PL/SQL Block级别),而Nested table与VARRAY则可以使用CREATE TYPE进行创建(即适用范围是Schema级别),它们还可以直接作为数据库表中列的类型。
BTW,为了避免误解,以下显式提到“索引”的地方,并非指的是数据库表的索引,而是特指访问集合元素时使用的“下标”,即Collection_Name(index)中的index。
2)集合类型的声明与初始化
2.1)Associative array
首先看一下Associative array的声明及初始化,示例中的第一部分显示,Associative array不能使用CREATE TYPE来创建。第二部分使用一个匿名PL/SQL块来演示Associative array使用,可以看到用法还是相对简单的。
Associative array的索引可以是稀疏的(即可以不连续)。
SQL
>
CREATE
OR
REPLACE
TYPE ib_planguage
IS
TABLE
OF
VARCHAR2
(
10
)
INDEX
BY
PLS_INTEGER;
2
/
Warning: Type created
with
compilation errors.
SQL
>
SHOW ERROR;
Errors
for
TYPE IB_PLANGUAGE:
LINE
/
COL ERROR
—
—— —————————————————————–
0
/
0
PL
/
SQL: Compilation unit analysis terminated
1
/
22
PLS
–
00355
:
use
of
pl
/
sql
table
not
allowed
in
this context
DECLARE
TYPE ib_planguage
IS
TABLE
OF
VARCHAR2
(
10
)
INDEX
BY
PLS_INTEGER;
lang ib_planguage;
idx PLS_INTEGER;
BEGIN
lang(
1
):
=
‘
java
‘
;
lang(
9
):
=
‘
c#
‘
;
lang(
3
):
=
‘
c++
‘
;
idx:
=
lang.FIRST;
WHILE
(idx
IS
NOT
NULL
) LOOP
DBMS_OUTPUT.PUT_LINE(lang(idx));
idx:
=
lang.
NEXT
(idx);
END
LOOP;
END
;
SQL
>
/
java
c
++
c#
2.2)Nested table
接着来看Nested table的声明及初始化,Nested table既可以通过CREATE TYPE声明成全局类型,也可以在PL/SQL块中声明块级别的类型。
与Associative array不同,Nested table变量需要显式初始化,其语法类似于C#,只是不用new关键字。额外地,Nested table初始化之后还需要调用EXTEND过程,扩展此集合的“容量”。
示例的第二部分提供了一种相对简单的初始化方法,即可以在构造器中直接传入集合成员。这种简便的初始化方法不适用于Associative array。
SQL
>
CREATE
OR
REPLACE
TYPE nt_planguage
IS
TABLE
OF
VARCHAR2
(
10
);
2
/
Type created.
DECLARE
lang nt_planguage;
BEGIN
lang:
=
nt_planguage();
lang.EXTEND(
3
);
lang(
1
):
=
‘
java
‘
;
lang(
2
):
=
‘
c#
‘
;
lang(
3
):
=
‘
c++
‘
;
FOR
i
IN
1
..lang.
COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(lang(i));
END
LOOP;
END
;
SQL
>
/
java
c#
c
++
或者可以简单地写成:
DECLARE
lang nt_planguage;
BEGIN
lang:
=
nt_planguage(
‘
java
‘
,
‘
c#
‘
,
‘
c++
‘
);
FOR
i
IN
1
..lang.
COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(lang(i));
END
LOOP;
END
;
2.3)VARRAY
最后我们来看VARRAY的声明及初始化,它与Nested table比较类似,但仍然存在一些区别,包括(1)VARRAY可以在声明时限制集合的长度,EXTEND的长度不能大于集合声明时的长度(下例中长度是8),但是在给集合成员赋值时,以EXTEND为准,例如下例中可以使用的只有3个集合成员。;(2)其索引总是连续的,而Nested table的索引在初始化赋值时是连续的,不过随着集合元素被删除,可能变得不连续。
SQL
>
CREATE
OR
REPLACE
TYPE va_planguage
IS
VARRAY(
8
)
OF
VARCHAR2
(
10
);
2
/
Type created.
DECLARE
lang va_planguage;
BEGIN
lang:
=
va_planguage();
lang.EXTEND(
3
);
lang(
1
):
=
‘
java
‘
;
lang(
2
):
=
‘
c#
‘
;
lang(
3
):
=
‘
c++
‘
;
FOR
i
IN
1
..lang.
COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(lang(i));
END LOOP;
END;
同样,也可以简单地写成:
DECLARE
lang va_planguage;
BEGIN
lang:
=
va_planguage(
‘
java
‘
,
‘
c#
‘
,
‘
c++
‘
);
FOR
i
IN
1
..lang.
COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(lang(i));
END
LOOP;
END
;
3)如何选择适用的集合类型
通常来说,对集合类型的第一选择应该是Associative array,因为它不需要初始化或者EXTEND操作,并且是迄今为止最高效的集合类型。唯一不足的一点是它只能用于PL/SQL而不能直接用于数据库。
如果你需要允许使用负数索引,应该选择Associative array;
如果你需要使用10g,11g中的那些集合操作,应该选择Nested table;
如果你需要限制集合元素的个数,应该选择VARRAY
4)其它
一个非常令人费解的地方是,位于PL/SQL语句块中的TYPE声明,必须使用关键字IS,而不能使用AS,但是在使用CREATE TYPE声明全局类型时,这两个是通用的。
本来,说到这里就应该介绍完了,但是,Oracle引入了OO,导致我还要稍微说一下Object的声明及初始化,因为在某些情况下,你还会遇到集合成员是对象类型的情况。
SQL
>
CREATE
OR
REPLACE
TYPE o_planguage
IS
OBJECT(lang
VARCHAR2
(
10
),lang_desc
VARCHAR2
(
100
));
2
/
Type created.
DECLARE
lang o_planguage;
BEGIN
lang:
=
o_planguage(
‘
java
‘
,
‘
java is an OO programming language…
‘);
DBMS_OUTPUT.PUT_LINE(lang.lang_desc);
END;
注意,Object不能在PL/SQL语句块中声明。
注意2,我们不能使用如下代码进行初始化:
lang:=o_planguage();
lang.lang:=’java’;
lang.lang_desc:=’java is an OO programming language…’
这样的语法会导致出现{PLS-00306: 调用 ‘lang’ 时参数个数或类型错误},即Object类型没有默认的无参构造器。介绍完这个,那么即使集合的成员是Object时,也可以如法炮制去声明、初始化了。