7.2.3 复合类型的变量

所谓复合类型的变量,就是每变量包含几个元素,可以存储多个值。这种变量类型同标量类型使用方式稍有差异,复合类型需要先定义,然后才能声明该类型的变量。最常用的是三种类型,一种是记录类型;一种是索引表类型;还有一种是VARRAY数组。

1.PL/SQL“记录类型”

该类型可以包含一个或多个成员,而每个成员的类型可以不同,成员可以是标量类型,也可以是引用其他变量的类型(使用%TYPE)。该类型比较适合处理查询语句中有多个列的情况。最常用的就是在调用某张表中的一行记录时,利用该类型变量存储这行记录。如果想要调用其中的数据,可以用“变量名称.成员名称”的格式进行调用。“记录类型”有两种声明的方式。

1)第一种声明语法如下:


01 TYPE type_name IS RECORD

02 (

03 field_name datatype

04 [

05 [NOT NULL]

06 {:=|DEFAULT}expression

07 ]

08 [,field_name datatype[[NOT NULL]{:=|DEFAULT}expression]…

09 );


【语法说明】

❑第1行的type_name表示定义的记录类型的名称。其余都是关键词。

❑第3行的field_name表示行记录的成员名称,datatype表示行记录成员数据类型。

❑第5行的[NOT NULL]表示可选部分,可以约束记录的成员非空。

❑第6行的{:=|DEFAULT}表示为记录成员赋值,expression为赋值表达式。

❑第8行同第3~7行表示的含义相同,这么写是让读者明白,记录类型里可以有多个成员。

从上面语法介绍中可以看出记录类型可以包含多个成员,而其成员的定义方式和前面介绍的标量定义方式相同。

【示例6】定义“记录类型”的变量

下面一段PL/SQL脚本将演示如何定义PL/SQL记录类型的变量。


01 DECLARE

02 TYPE product_rec IS RECORD

03 (

04 v_productid productinfo.productid%TYPE,—产品ID

05 v_productname VARCHAR2(20),—产品名称

06 v_productprice NUMBER(8,2)—价格

07 );

08

09 v_product product_rec;—记录类型变量

10 BEGIN

11 SELECT productid,productname,productprice

12 INTO v_product

13 FROM productinfo

14 WHERE productid='0240040001';

15

16 DBMS_OUTPUT.PUT_LINE('productid='||v_product.v_productid);

17 DBMS_OUTPUT.PUT_LINE('productname='||v_product.v_productname);

18 DBMS_OUTPUT.PUT_LINE('productid='||v_product.v_productprice);

19 END;

20 /


【代码解析】

❑第1~9行是PL/SQL块的声明部分,第10~19行是PL/SQL块的执行体部分。

❑第2~7行属于声明行记录类型。第2行product_rec是行记录的名称。

❑第4~6行表示在行记录中包含了3个成员。这3个成员声明方式同标量类型声明方式一致。从中可以看出它的成员也可以利用%TYPE来声明变量类型。

❑第9行表示声明变量v_product,它的数据类型是product_rec类型。

❑第11~14行利用SELECT…INTO语句为变量赋值,这里INTO后面直接是v_product记录类型,这样赋值会依据声明记录类型时里面成员的顺序依次赋值。这种赋值方式比较方便。

❑第16~18行表示输出结果。

【执行效果】

打开SQL*Plus,首先设置输出参数为TRUE,也就是SET SERVEROUTPUT ON语句。然后执行脚本,执行过程见图7.7。

7.2.3 复合类型的变量 - 图1

图 7.7 记录类型的变量执行过程

2)利用%ROWTYPE声明记录类型数据。

前面已经介绍过“记录类型”的变量,该类型是提取行记录时常用的存储数据的方式。除了上面的直接声明方式外还有一种声明记录类型的方式,就是利用%ROWTYPE。这种声明方式可以直接引用表中的行作为变量类型。它同%TYPE类似,可以避免因表中字段的数据类型改变而导致PL/SQL块出错的问题。

【示例7】%ROWTYPE示例

示例将演示如何利用%ROWTYPE声明变量类型。具体脚本如下:


01 DECLARE

02 v_product productinfo%ROWTYPE;

03 BEGIN

04 SELECT*INTO v_product

05 FROM productinfo

06 WHERE productid='0240040001';

07 DBMS_OUTPUT.PUT_LINE('productid='||v_product.productid);

08 DBMS_OUTPUT.PUT_LINE('productname='||v_product.productname);

09 DBMS_OUTPUT.PUT_LINE('productid='||v_product.productprice);

10 END;

11 /


【代码解析】

❑第2行声明名称为v_product的变量,其数据类型是表productinfo的行记录类型。这里利用了%ROWTYPE方式声明变量数据类型。

❑第4~6行表示把查询出来的数据存储到变量v_product中。其中从第4行可以看出,这里查询了一行记录,它可以直接把这行记录放进v_product里。

❑第7~9行表示输出结果,提取结果的方式就是前面介绍过的“变量名称.成员名称”。

【执行结果】

打开SQL*Plus执行以上脚本,结果见图7.8。

7.2.3 复合类型的变量 - 图2

图 7.8 利用%ROWTYPE方式声明变量

从执行结果可以看出,它同上一个示例最后结果没有区别,但是这个示例却使用更少的代码完成了同一个功能。

2.PL/SQL索引表类型(关联数组)

该类型和数组相似,它利用键值查找对应的值。这里键值同真正数组的下标不同,索引表中下标允许使用字符串。数组的长度不是固定值,它可以根据需要自动增长。其中的键值是整数或字符串。而其中的值就是普通的标量类型,也可以是记录类型。可以利用“变量名称(键值)”为其赋值或取值,如果某个键值的指向已经有数据了,那么该操作就是更改已有的数据。具体语法如下:


01 TYPE type_name IS TABLE OF

02 {

03 column_type|

04 variable_name%TYPE|

05 table_name.column_name%TYPE|

06 table_name%ROWTYPE

07 }

08 [NOT NULL]

09 INDEX BY{PLS_INTEGER|BINARY_INTEGER|VARCHAR2(v_size)}


【代码解析】

❑第1行的type_name表示该类型的名称。其他为固有关键词。

❑第3~6行表示索引表中的数据类型。其中,第3行表示标量数据类型,第4和5行表示利用%TYPE引用类型,第6行利用ROWTYPE引用类型。这在下面的示例中将看到。

❑第8行表示是否可以为空的约束。

❑第9行表示数组下标的数据类型。

以上的语法只是索引表类型本身的定义语法,并没有包含变量的定义。实际上,这里和变量的定义没有关系。如果想把某个变量声明成索引表类型,按照下面语法就好:


variable_name type_name;


其中,variable_name就是变量的名称,而type_name就是索引表的名称。日常开发中可以选择用数字作为键值或以字符串作为键值。下面的两个示例将演示如何使用这两种方式操作。

【示例8】数字为键值的索引表示例

示例演示以数字为键值的索引表操作过程。具体脚本如下:


01 DECLARE

02 TYPE prodt_tab_fst IS TABLE OF productinfo%ROWTYPE—%ROWTYPE

03 INDEX BY BINARY_INTEGER;—BINARY_INTEGER

04

05 TYPE prodt_tab_sec IS TABLE OF VARCHAR2(8)

06 INDEX BY PLS_INTEGER;—PLS_INTEGER

07

08 v_prt_row prodt_tab_fst;

09 v_prt prodt_tab_sec;

10

11 BEGIN

12 v_prt(1):='正数';

13 v_prt(-1):='负数';

14

15 SELECT*INTO v_prt_row(1)

16 FROM productinfo

17 WHERE productid='0240040001';

18

19 DBMS_OUTPUT.PUT_LINE('行数据-v_prt_row(1)='||v_prt_row(1).productid

20 ||'—-'

21 ||v_prt_row(1).productname);

22

23 DBMS_OUTPUT.PUT_LINE('v_prt(1)='||v_prt(1));

24 DBMS_OUTPUT.PUT_LINE('v_prt(-1)='||v_prt('-1'));

25 END;

26 /


【代码解析】

❑第2~3行表示声明一个索引表,名称为prodt_tab_fst。第2行表示以%ROWTYPE方式声明。也就是说,prodt_tab_fst中的元素都是productinfo的行记录。这在下面赋值的时候可以看出来。第3行表示以BINARY_INTEGER类型为索引,可以认为是键值,是BINARY_INTEGER类型。

❑第5~6行表示声明另一个索引表,名称为prodt_tab_sec。第5行表示该索引表元素的类型是VARCHAR2类型。第6行表示该索引表以PLS_INTEGER类型为索引。前面介绍过,该类型同BINARY_INTEGER类型区别不大,甚至认为是一样的。

❑第8行表示声明变量,该变量的类型是prodt_tab_fst。

❑第9行同样表示声明变量,其类型为prodt_tab_sec。

❑第12~13行表示为变量v_prt赋值。可以看到,它赋值的方式同数组类似,以“变量名(索引)”的形式赋值,当取值时也需要同样的规则。

❑第15~17行利用SELECT…INTO语句为变量v_prt_row赋值。从中可以看出它把productinfo表的一行记录存储到了变量中。

❑第19~24行表示把存储的数据输出到屏幕。

【执行效果】

在SQL*Plus中执行以上脚本,并查看执行结果。执行过程见图7.9。

7.2.3 复合类型的变量 - 图3

图 7.9 数字为键值的索引表使用过程

以上示例使用数字作为索引类型,也是比较常用的一种方式。但是,索引表还支持一种以字符串为键值的索引方式。

【示例9】字符串为键值的索引表

示例将演示以字符串为键值的索引表如何操作。具体脚本如下:


01 DECLARE

02 TYPE prodt_tab_thd IS TABLE OF NUMBER(8)

03 INDEX BY VARCHAR2(20);—INDEX BY VARCHAR2(20)

04 v_prt_chr prodt_tab_thd;

05

06 BEGIN

07 v_prt_chr('test'):=123;

08 v_prt_chr('test1'):=0;

09

10 DBMS_OUTPUT.PUT_LINE('v_prt_chr(123)='||v_prt_chr('test'));

11 DBMS_OUTPUT.PUT_LINE('v_prt_chr(000)='||v_prt_chr('test1'));

12 DBMS_OUTPUT.PUT_LINE('v_prt_chr(000)='||v_prt_chr.first);

13 DBMS_OUTPUT.PUT_LINE('v_prt_chr(000)='||v_prt_chr(v_prt_chr.first));

14 END;

15 /


【代码解析】

❑第2~3行表示创建索引表。其名称为prodt_tab_thd,索引键值为字符串型。

❑第4行声明变量,类型为表类型。

❑第7~8行为变量赋值,因为是字符串类型的键值,所以允许以示例中的格式赋值。

❑第10~13行表示输出屏幕结果。从中可以看到以“变量名称.first”的格式得到第一个或最后一个键值。

【执行效果】

在SQL*Plus中执行该示例脚本,执行过程见图7.10。

7.2.3 复合类型的变量 - 图4

图 7.10 字符串为键值的索引表使用过程

3.VARRAY变长数组

该类型的元素个数是需要限制的,它是一个存储有序元素的集合。集合下标从1开始,比较适合较少的数据使用。声明语法如下:


TYPE type_name IS{VARRAY|VARYING ARRAY}(size_limit)

OF element_type[NOT NULL]


【语法说明】

❑type_name:表示该数组的名称。

❑{VARRAY|VARYING ARRAY}:必选项,二选一,表示数组类型。

❑size_limit:该数组的长度。

❑element_type:数组里元素的类型。

【示例10】VARRAY数组示例

示例将演示如何声明该类型的变量。脚本如下:


01 DECLARE

02 TYPE varr IS VARRAY(100)OF VARCHAR2(20);

03

04 v_product varr:=varr('1','2');

05 BEGIN

06 v_product(1):='THIS IS A';

07 v_product(2):='TEST';

08 DBMS_OUTPUT.PUT_LINE('productid='||v_product(1));

09 DBMS_OUTPUT.PUT_LINE('productid='||v_product(2));

10 END;

11 /


【代码解析】

❑第2行表示声明VARRAY数组,数组长度为100,名称是varr,元素为VARCHAR2类型,长度为20。

❑第4行表示声明变量,变量名称为v_product,其类型为varr类型,该类型被初始化了两个元素(最多可初始化100个)。也就是说,只能向v_product中下标为1和2的元素赋值。

❑第6~7行表示为数组元素赋值。

❑第8~9行表示输出数组元素的值。

【执行效果】

在SQL*Plus中执行该示例脚本,执行过程见图7.11。

7.2.3 复合类型的变量 - 图5

图 7.11 变量为VARRAY数组类型演示