|
| 1 | +## [转载] Oracle record、varray、table和%type、%rowtype的使用详解 |
| 2 | + |
| 3 | +### 作者 |
| 4 | +digoal |
| 5 | + |
| 6 | +### 日期 |
| 7 | +2018-04-23 |
| 8 | + |
| 9 | +### 标签 |
| 10 | +PostgreSQL , Oracle , PL/SQL |
| 11 | + |
| 12 | +---- |
| 13 | + |
| 14 | +## 背景 |
| 15 | +## 原文 |
| 16 | +http://www.ibloger.net/article/230.html |
| 17 | + |
| 18 | +## 1 说明 |
| 19 | +### 1.1 RECORD |
| 20 | +定义记录数据类型。它类似于c语言中的结构数据类型(structure),pl/sql提供了将几个相关的、分离的、基本数据类型的变量组成一个整体的方法,即record复合数据类型。在使用记录数据类型变量时,需要在声明部分先定义记录的组成、记录的变量,然后在执行部分引用该记录变量本身或其中的成员。 |
| 21 | + |
| 22 | +定义记录数据类型的语法如下: |
| 23 | + |
| 24 | +``` |
| 25 | +type record_name is record( |
| 26 | + v1 data_type1 [not null][:=default_value], |
| 27 | + v2 data_type2 [not null][:=default_value], |
| 28 | + vn data_typen [not null][:=default_value] |
| 29 | +); |
| 30 | +``` |
| 31 | + |
| 32 | +### 1.2 VARRAY |
| 33 | +数组是具有相同数据类型的一组成员的集合。每个成员都有一个唯一的下标,它取决于成员在数组中的位置。在pl/sql中,数组数据类型是varray(variable array,即可变数组)。 |
| 34 | + |
| 35 | +定义varray数据类型的语法如下: |
| 36 | + |
| 37 | +``` |
| 38 | +type varray_nameis varray(size) of element_type [not null]; |
| 39 | +``` |
| 40 | + |
| 41 | +其中,varray_name是varray数据类型的名称,size是正整数,表示可以容纳的成员的最大数量,每个成员的数据类型是element_typeo默认时,成员可以取空值,否则需要使用not null加以限制。 |
| 42 | + |
| 43 | +### 1.3 TABLE |
| 44 | +定义记录表(或索引表)数据类型。它与记录类型相似,但它是对记录类型的扩展。它可以处理多行记录,类似于c语言中的二维数组,使得可以在pl/sql中模仿数据库中的表。 |
| 45 | + |
| 46 | +定义记录表类型的语法如下: |
| 47 | + |
| 48 | +``` |
| 49 | + type table name is table of element_type [not null] |
| 50 | + index by [binary_integer|pls_integer|varray2]; |
| 51 | +``` |
| 52 | + |
| 53 | +关键字index by表示创建一个主键索引,以便引用记录表变量中的特定行。 |
| 54 | + |
| 55 | +binary_integer的说明 |
| 56 | + |
| 57 | +如语句:type numbers is table of number index by binary_integer;其作用是,加了”index bybinary_integer ”后,numbers类型的下标就是自增长,numbers类型在插入元素时,不需要初始化,不需要每次extend增加一个空间。 |
| 58 | + |
| 59 | +而如果没有这句话“indexby binary_integer”,那就得要显示对初始化,且每插入一个元素到numbers类型的table中时,都需要先extend。 |
| 60 | + |
| 61 | +## 2 举例 |
| 62 | +### 2.1 创建表结构以及数据准备 |
| 63 | +``` |
| 64 | +--组织机构结构表 |
| 65 | +create table sf_org( |
| 66 | + org_id int not null, --组织机构主键id |
| 67 | + org_name varchar2(50),--组织机构名称 |
| 68 | + parent_id int--组织机构的父级 |
| 69 | +) |
| 70 | + |
| 71 | +--一级组织机构 |
| 72 | +insert into sf_org(org_id, org_name, parent_id) values(1, '一级部门1',0); |
| 73 | + |
| 74 | +--二级部门 |
| 75 | + |
| 76 | +insert into sf_org(org_id, org_name, parent_id) values(2, '二级部门2',1); |
| 77 | +insert into sf_org(org_id, org_name, parent_id) values(3, '二级部门3',1); |
| 78 | +insert into sf_org(org_id, org_name, parent_id) values(4, '二级部门4',1); |
| 79 | +``` |
| 80 | + |
| 81 | +### 2.2 RECORD的使用举例 |
| 82 | +先定义一个只与sf_org表中某几个列的数据类型相同的记录数据类型type_org_record,然后声明一个该数据类型的记录变量v_org_record,最后用替换变量&org_id接受输入的雇员编码,查询并显示该雇员的这几列中的信息。注意,在使用record数据类型的变量时要用“.”运算符指定记录变量名限定词。 |
| 83 | + |
| 84 | +一个记录类型的变量只能保存从数据库中查询出的一行记录,如果查询出了多行记录,就会出现错误。 |
| 85 | + |
| 86 | +``` |
| 87 | +-- RECORD的使用举例 |
| 88 | +declare |
| 89 | + type type_org_record is record( |
| 90 | + v_name sf_org.org_name%type, |
| 91 | + v_parent sf_org.parent_id%type); |
| 92 | + |
| 93 | + v_record type_org_record; |
| 94 | +begin |
| 95 | + select org_name, parent_id into v_record from sf_org so |
| 96 | + where so.org_id = &org_id; |
| 97 | + dbms_output.put_line('部门名称:' || v_record.v_name); |
| 98 | + dbms_output.put_line('上级部门编码:' || to_char(v_record.v_parent)); |
| 99 | +end; |
| 100 | +``` |
| 101 | + |
| 102 | +执行时会弹出一个输入框,如下图,执行完毕以后可以在输出中查看效果 |
| 103 | + |
| 104 | + |
| 105 | + |
| 106 | + |
| 107 | + |
| 108 | +### 2.3 VARRAY的使用举例 |
| 109 | +先定义一个能保存5个varchar2(25)数据类型的成员的varray数据类型org_varray_type,然后声明一个该数据类型的varray变量v_org_varray,最后用与org_varray_type数据类型同名的构造函数语法给v_org_varray变量赋予初值并显示赋值结果。 |
| 110 | + |
| 111 | +注意,在引用数组中的成员时.需要在一对括号中使用顺序下标,下标从1开始而不是从0开始。 |
| 112 | + |
| 113 | +``` |
| 114 | +--- VARRAY的使用举例 |
| 115 | +declare |
| 116 | + type org_varray_type is varray(5) of varchar2(25); |
| 117 | + v_arr_set org_varray_type; |
| 118 | +begin |
| 119 | + v_arr_set := org_varray_type('1','2','3','4','5'); |
| 120 | + dbms_output.put_line('输出1:' || v_arr_set(1) || '、'|| v_arr_set(2) || '、'|| v_arr_set(3) || '、'|| v_arr_set(4)); |
| 121 | + dbms_output.put_line('输出2:' || v_arr_set(5)); |
| 122 | + v_arr_set(5) := '5001'; |
| 123 | + dbms_output.put_line('输出3:' || v_arr_set(5)); |
| 124 | +end; |
| 125 | +``` |
| 126 | + |
| 127 | + |
| 128 | + |
| 129 | +### 2.4 TABLE使用举例 |
| 130 | +#### 2.4.1 存储单列多行 |
| 131 | +这个和varray类似。但是赋值方式稍微有点不同,不能使用同名的构造函数进行赋值。具体的如下: |
| 132 | + |
| 133 | +``` |
| 134 | +-- 存储单列多行 |
| 135 | +declare |
| 136 | + type org_table_type is table of varchar2(25) |
| 137 | + index by binary_integer; |
| 138 | + v_org_table org_table_type; |
| 139 | +begin |
| 140 | + v_org_table(1) := '1'; |
| 141 | + v_org_table(2) := '2'; |
| 142 | + v_org_table(3) := '3'; |
| 143 | + v_org_table(4) := '4'; |
| 144 | + v_org_table(5) := '5'; |
| 145 | + dbms_output.put_line('输出1:' || v_org_table(1) || '、'|| v_org_table(2) || '、'|| v_org_table(3) || '、'|| v_org_table(4)||'、'|| v_org_table(5)); |
| 146 | +end; |
| 147 | +``` |
| 148 | + |
| 149 | +#### 2.4.2 存储多列多行和ROWTYPE结合使用 |
| 150 | +采用bulkcollect可以将查询结果一次性地加载到collections中。而不是通过cursor一条一条地处理。 |
| 151 | + |
| 152 | +``` |
| 153 | +-- 存储多列多行和rowtype结合使用 |
| 154 | +declare |
| 155 | + type t_type is table of sf_org%rowtype; |
| 156 | + v_type t_type; |
| 157 | + begin |
| 158 | + select org_id, org_name, parent_id bulk collect into v_type from sf_org where sf_org.org_id <= 3; |
| 159 | + |
| 160 | + for v_index in v_type.first .. v_type.last loop |
| 161 | + dbms_output.put_line(v_type(v_index).org_id ||' '|| v_type(v_index).org_name ||' '|| v_type(v_index).parent_id ); |
| 162 | + end loop; |
| 163 | + end; |
| 164 | +``` |
| 165 | + |
| 166 | + |
| 167 | + |
| 168 | +#### 2.4.3 存储多列多行和RECORD结合使用 |
| 169 | +采用bulkcollect可以将查询结果一次性地加载到collections中。而不是通过cursor一条一条地处理。 |
| 170 | + |
| 171 | +``` |
| 172 | +-- 存储多列多行和RECORD结合使用 |
| 173 | +declare |
| 174 | + type test_emp is record |
| 175 | + ( |
| 176 | + c1 sf_org.org_name%type, |
| 177 | + c2 sf_org.parent_id%type |
| 178 | + ); |
| 179 | + type t_type is table of test_emp; |
| 180 | + v_type t_type; |
| 181 | + begin |
| 182 | + select org_name, parent_id bulk collect into v_type from sf_org where sf_org.org_id <= 3; |
| 183 | + |
| 184 | + for v_index in v_type.first .. v_type.last loop |
| 185 | + dbms_output.put_line(v_type(v_index).c1 || ' ' || v_type(v_index).c2); |
| 186 | + end loop; |
| 187 | + end; |
| 188 | +``` |
| 189 | + |
| 190 | + |
| 191 | + |
| 192 | +## 3 问题 |
| 193 | +varry和table集合不能直接对其进行查询。只能对其进行遍历。 |
| 194 | + |
| 195 | +## 4 其他 |
| 196 | +在我的Oracle 创建 split 和 splitstr 函数文章中,有包含table的查询示例图: |
| 197 | + |
| 198 | +http://www.ibloger.net/article/232.html |
| 199 | + |
| 200 | +```%TYPE```说明 |
| 201 | + |
| 202 | +为了使一个变量的数据类型与另一个已经定义了的变量(尤其是表的某一列)的数据类型相一致,Oracle提供了```%TYPE```定义方式。当被参照的那个变量的数据类型改变了之后,这个新定义的变量的数据类型会自动跟随其改变,容易保持一致,也不用修改PL/SQL程序了。当不能确切地知道被参照的那个变量的数据类型时,就只能采用这种方法定义变量的数据类型。 |
| 203 | + |
| 204 | +```%ROWTYP```说明 |
| 205 | + |
| 206 | +如果一个表有较多的列,使用%rowtype来定义一个表示表中一行记录的变量,比分别使用```%type```来定义表示表中各个列的变量要简洁得多,并且不容易遗漏、出错。这样会增加程序的可维护性。 |
| 207 | + |
| 208 | +为了使一个变量的数据类型与一个表中记录的各个列的数据类型相对应、一致,oracle提供```%rowtype```定义方式。当表的某些列的数据类型改变了之后,这个新定义的变量的数据类型会自动跟随其改变,容易保持一致,也不用修改pl/sql程序了。当不能确切地知道被参照的那个表的结构及其数据类型时,就只能采用这种方法定义变量的数据类型。 |
| 209 | + |
| 210 | +<a rel="nofollow" href="http://info.flagcounter.com/h9V1" ><img src="http://s03.flagcounter.com/count/h9V1/bg_FFFFFF/txt_000000/border_CCCCCC/columns_2/maxflags_12/viewers_0/labels_0/pageviews_0/flags_0/" alt="Flag Counter" border="0" ></a> |
| 211 | + |
0 commit comments