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.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.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.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.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.11 变量为VARRAY数组类型演示