Oracle 複合數據類型專題之PLSQL集合數據類型

Oracle PL/SQL集合數據類型專題:


一、什麼是PL/SQL集合數據類型
PL/SQL複合數據類型包括:PL/SQL記錄、PL/SQL集合(分爲PL/SQL表(別名索引表)、嵌套表、VARRAY)。
其中PL/SQL集合數據類型是指符合數據類型中的PL/SQL集合。


複合數據類型的說明在本博客的《PLSQL數據類型》中有詳述,這裏只對PL/SQL集合數據類型的一系列特有操作與應用做講述。




二、PL/SQL集合的多級集合調用應用
說明:多級集合是指嵌套了集合類型的集合類型,從而實現多維數組功能,9i後支持。


1)多級PL/SQL表(索引表)
說明:如果多維數組元素個數沒有限制,可以使用多級PL/SQL表和嵌套表。
Declare
Type al_table_type is table of int index by binary_integer; --定義一維table
Type nal_table_type is table of al_table_type index by binary_integer;--定義二維table集合
Nv1 nal_table_type;
Begin
Nv1(1)(1):=10; 
Nv1(1)(2):=5;                                                                                                
Nv1(2)(1):=100; 
Nv1(2)(2):=50;
Dbms_output.put_line(‘顯示二維數組所有元素’);
For I in 1..nv1.count loop
  For j in 1..nu1(i).count loop
    Dbms_output.put_line(i||’,’||j||’shi’||nv1(i)(j));
  End loop;
End loop;
End;


2)多級嵌套表
Declare
Type al_table_type is table of int;--定義一維嵌套表
Type nal_table_type is table of al_table_type;--定義二維嵌套表集合
Nv1 nal_table_typer :=nal_table_typer (al_table_type(2,4),al_table_type(5,73));
Begin
Dbms_output.put_line(‘顯示二維數組所有元素’);
For I in 1..nv1.count loop
  For j in 1..nv1(i).count loop
    Dbms_output.put_line(i||’,’||j||’shi’||nv1(i)(j));
  End loop;
End loop;
End;


3)多級VARRAY
Declare
Type al_varray_type is varray(10) of int;--定義一維varray
Type nal_varray_type is varray(10) of al_varray_type;--定義二維varray集合
nvl nal_varray_type:= nal_varray_type(
al_varray_type(58,100,102);
al_varray_type(55,6,73);
al_varray_type(2,4);
begin
dbms_output.put_line(‘顯示二維數組所有元素’);
for i in 1..nv1.count loop
  for j in 1..nv1.count loop
    Dbms_output.put_line(i||’,’||j||’shi’||nv1(i)(j));
  End loop;
End loop;
End;




三、集合數據類型的方法
說明:複合數據類型中PL/SQL集合類型所特有的集合方法,集合方法是Oracle所提供用於操縱集合變量的內置函數或過程。
方法包含EXISTS、COUNT、LIMIT、FIRST、NEXT、PRIOR和NEXT是函數,EXTEND、TRIM和DELETE是過程。


1、exists方法
說明:確定特定的PL/SQL表元素是否存在,如果集合元素存在,則返回true;如果不存在,則返回false
例子:
declare
type ename_table_type is table of emp.ename%type;
ename_table ename_table_type;
begin
if ename_table.exsts(1) then
ename_table(1):='scott';
else
dbms_output.put_line('必須初始化集合元素');


2、count方法
說明:返回當前集合變量中的元素總個數。
declare
type aneme_table_type is table of emp.ename%type index by binary_integer;
ename_table ename_table_type;
begin
ename_table(-5):='aa';
ename_table(1):='b';
ename_table(10):='bk';
dbms_output.put_line(ename_table.count);
end;


3、limit方法
說明:返回集合元素的最大元素個數。因爲嵌套表和索引表的元素個數沒有限制,所以調用方法會返回NULL;而對於VARRAY會返回最大元素個數。
declare
type aneme_table_type is varray(20) of emp.ename%type;
ename_table ename_table_type:=ename_table_type('mary');
begin
dbms_output.put_line(ename_table_type.limit);
end;


4、first和last方法
說明:返回集合第一個、最後一個元素的下標。
declare
type aneme_table_type is table of emp.ename%type index by binary_integer;
ename_table ename_table_type;
begin
ename_table(-5):='aa';
ename_table(1):='b';
ename_table(10):='bk';
dbms_output.put_line(ename_table.first);
dbms_output.put_line(ename_table.last);
end;


5、prior和next方法
說明:返回當前集合元素的前一個元素和下一個元素


舉例:
declare
type ename_table_type is table of emp.ename%type index by benary_integer; --PL/SQL表
ett ename_table_type;
begin
et(-5):='scott';
et(1):='smith';
st(5):='mary';
dbms_output.put_line('元素1的前一個元素值:' || et(et.prior(1))); --結果是scott
dbms_output.put_line('元素1的後一個元素值:' || et(et.next(1))); --結果是mary
end;


6、extend方法
說明:爲集合變量增加元素,只適用於嵌套表和VARRAY。
格式:extend 添加一個null元素
extend(n) 添加n個null元素
extend(n,i) 添加n個值與第i個元素相同的元素


舉例:
declare
type id_table_type is table of number(6); --嵌套表
idt id_table_type:=id_table_type(1,2,5); --聲明並初始化3個元素
begin
if idt.exists(4) then --判讀第四個元素是否存在
dbms_output.put_line('元素值:' || idt(no));
else
dbms_output.put_line('元素未初始化'); --結果
end if;
idt.extend(999); --添加999個空元素
dbms_output.put_line('第一個元素是:' || idt(idt.first)); --結果爲1
dbms_output.put_line('最後一個元素是:' || nvl(to_char(idt(idt.first)),'null')); --結果爲null
dbms_output.put_line('元素總數爲:' || idt.count); --結果爲1002
end;


7、trim方法
說明:從集合尾部刪除元素,只適用於嵌套表和VARRAY。
格式:trim 刪除一個元素
trim(n) 刪除n個


舉例:
declare
type id_array_type is varray(30) of number(6); --可變長數組
iat id_array_type:=id_array_type('A','B','C','D','E','F','G','H','I','J','K','L');
begin
dbms_output.put_line('元素總數爲:' || iat.count); --結果爲12
dbms_output.put_line('最大元素個數:' || iat.limit); --結果是30
iat.trim(5);
dbms_output.put_line('最後一個元素:' || iat(iat.last)); --結果是G
end;


8、delete方法
說明:刪除集合元素,只適用於嵌套表和索引表。
格式:delete 刪除全部元素
delete(n) 刪除第N個元素
delete(m,n) 刪除除集合變量中m~n之間的所有元素


舉例:
declare
type id_table_type is table of number(6) index by binary_integer; --PL/SQL表
itt id_table_type;
begin
for i in 1..10000 loop
itt(i):=i;
end loop;
for j in 1..itt.count loop
if mod(j,2)=0 then
id.delete(j); --餘數爲0則刪除該元素
end if;
end loop;
end;




四、集合數據類型的賦值。
當使用嵌套表和VARRAY時,通過執行insert、update、fetch、select,賦值語句,用可以將一個集合的數據賦值給另外一個集合。
從Oracle10g開始,給嵌套表賦值時,還可以用set、multiset union、multiset intersect、multiset except等集合操作符。
其中set用於取消嵌套表中的重複值,multiset union用於取得2個嵌套表的並集(帶有distinct可以取消重複結果)
multiset intersect取得2個嵌套表的交集,multiset except取得2個嵌套表的差集。


1、將一個集合的數據賦值給另外一個集合
說明:當使用賦值語句(:=)或sql語句將源集合中的數據賦值給目標集合時,會自動清除模板集合原有數據再賦值。
注意:當進行集合賦值時,源集合和目標集合的數據類型必須一致。
declare
type name_varray_type is varray(4) of varchar2(10);
name_array1 name_varray_type;
name_array2 name_varray_type;
begin
name_array1:=name_varray_type('scott','smith');
name_array2:=name_varray_type('a','a','a','a','a');
dbms_output.put('2的原數據:');
for i in 1..name_array2.count loop
dbms_output.put(name_array2(i));
end loop;
dbms_output.new_line;
name_array2:=name_array1;
dbms_output.put('2的新數據:');
for i in 1..name_array2.count loop
dbms_output.put(name_array2(i));
end loop;
dbms_output.new_line;
end;


2、給集合符NULL值
說明:在清空集合變量的所有數據時,既可以使用集合delete和trim,也可以講一個null集合變量賦給目標集合變量。
declare
type name_varray_type is varray(4) of varchar2(10);
name_array1 name_varray_type;
name_array2 name_varray_type;
begin
name_array1:=name_varray_type('scott','smith');
dbms_output.put('2的原數據個數'||name_array1.count);
name_array1:=name_array2;
--dbms_output.put('2的新數據個數'||name_array1.count);
end;


3、使用集合操作符給嵌套表賦值
說明:10g開始,允許將多個嵌套表的結果組合到某個嵌套表中,通過使用ANSI集合操作符(set,multiset union,
multiset intersect,multiset except)實現。


1)、set操作符
說明:用於去掉嵌套表中的重複值。
declare
type nt_table_type is table of number;
nt_table nt_table_type:=nt_table_type(2,4,3,1,2);
result nt_table_type;
begin
result:=set(nt_table);
dbms_output.put('result:');
for i in 1..result.count loop
dbms_output.put(' '||result(1));
end loop;
dbms_output.new_line;
end;


2)、multiset union和multiset union distinct操作符
說明:multiset union取得2個嵌套表的並集,保留重複項;multiset union distinct去掉重複。
declare 
type nt_table_type is table of numberr;
nt1 nt_table_type:=nt_table_type(1,2,3);
nt2 nt_table_type:=nt_table_type(3,4,5);
result nt_table_type;
begin
result:=nt1 multiset union nt2;
dbms_output.put('resilt:');
for i in 1..result.count loop
dbms_output.put(' '||result(i));
end loop;
dbms_output.new_line;
end;


3)、multiset intersect操作符
說明:取得2個嵌套表的交集。
declare 
type nt_table_type is table of numberr;
nt1 nt_table_type:=nt_table_type(1,2,3);
nt2 nt_table_type:=nt_table_type(3,4,5);
result nt_table_type;
begin
result:=nt1 multiset intersect nt2;
dbms_output.put('resilt:');
for i in 1..result.count loop
dbms_output.put(' '||result(i));
end loop;
dbms_output.new_line;
end;


4)、multiset except操作符
說明:取兩個嵌套表變量的差集。
declare 
type nt_table_type is table of numberr;
nt1 nt_table_type:=nt_table_type(1,2,3);
nt2 nt_table_type:=nt_table_type(3,4,5);
result nt_table_type;
begin
result:=nt1 multiset except nt2;
dbms_output.put('resilt:');
for i in 1..result.count loop
dbms_output.put(' '||result(i));
end loop;
dbms_output.new_line;
end;




五、集合數據類型的比較
說明:用於比較兩個集合變量是否相同。
10g後新增集合比較操作符包括:
CARDINALITY(返回嵌套表變量的元素個數),
SUBMULTISET OF(確定一個嵌套表是否爲領一個嵌套表的子集),
MEMBER OF(檢測特定數據是否爲嵌套表元素),
IS A SET(檢測嵌套表是否包含重複的元素),
IS EMPTY(檢測嵌套表是否爲null)等。


1、檢測集合是否爲null
說明:is null使用於嵌套表或VARRAY變量;is empty只使用於嵌套表。
declare
type name_array_type is varray(3) of varchar2(10);
name_array nane_array_type;
begin
--if name_array is empty then
if name_array is null then
dbms_output.put_line('未初始化');
end if;
end;


2、比較嵌套表是否相同
說明:使用=和!=比較嵌套表是否相同,只能用於嵌套表。
declare
type name_table_type is table of varchar2(10);
name_table1 name_table_type;
name_table2 name_table_type;
begin
name_table1:=name_table_type('scott');
name_table2:=name_table_tyoe('smith');
if name_table1=name_table2 then
dbms_output.put_line('相同');
else
dbms_output.put_line('不同');
end if;
end;


3、在嵌套表上使用ANSI集合操作符
說明:這些操作符只適用於嵌套表。


1)、CARDINALITY
說明:也可以稱爲函數,返回嵌套表變量的元素個數。
declare
type nt_table_type is table of number;
nt1 nt_table_tyoe:=nt_table_type(1,2,3,1);
begin
dbms_output.put_line('元素個數'||CARDINALITY(nt1));
end;


2)、SUBMULTISET OF
說明:用於確定一個嵌套表是否爲另一個嵌套表的子集。
declare
type nt_table_type is table of number;
nt1 nt_table_type:=nt_table_type(1,2,3);
nt2 nt_table_type:=nt_table_type(1,2,3);
begin
if nt1 submiltiset of nt2 then
dbms_output.put_line('nt1是nt2的子集');
end if;
end;


3)、MEMBER OF
說明:檢測特定數據是否爲嵌套表的元素。
declare
type nt_table_type is table of number;
nt1 nt_table_tyoe:=nt_table_tyoe(1,2,3,5);
v1 number:=2;
begin
if v1 member of nt1 then
dbms_output.put_line('v1是nt1的元素');
end if;
end;


4)、IS A SET
說明:用於檢測嵌套表是否包含重複的元素值。
declare
type nt_table_type is table of number;\
ot1 nt_table_type:=nt_table_type(1,2,3,5);
begin
if nt1 is a set then
dbms_output.put_line('嵌套表nt1無重複值');
end if;
end;




六、集合數據類型的批量綁定
說明:9i新增,是指執行單次SQL操作能傳遞所有集合的數據,當在select、insert、update、delete
語句上處理批量數據時,通過批量綁定,可以極大加快數據處理速度。
批量綁定用bult collect子句和forall語句完成,其中bult collect子句用於取得批量數據,
該子句只能用於select語句、fetch語句、dml返回子句中;而forall語句值適用於執行批量DML操作。


1、使用與不使用批量綁定的區別


1)、不適用批量綁定
說明:9i之前,爲了將多個集合元素插入到數據庫表,必須要使用循環完成。
例子:以索引表爲例
declare
type id_table_type id table of number(6) index by binary_integer;
type name_table_type is table of varchar2(10) index by binary_integer;
id_table id_table_type;
name_table name_table_type;
start_time number(10);
end_time number(10);
begin
for i in 1..5000 loop
id_table(i):=i;
name_table(i):='Name'||to_char(i);
end loop;
start_time:=dbms_utility.get_time;
for i in 1..id_table.count loop
insert into demo values(id_table(i),name_table(i));
end loop;
end_time:=dbms_utility.get_time;
dbms_output.put_line('總時間'||to_char((end_time-start_time)/100));
end;


2)、使用批量綁定
declare
type id_table_type id table of number(6) index by binary_integer;
type name_table_type is table of varchar2(10) index by binary_integer;
id_table id_table_type;
name_table name_table_type;
start_time number(10);
end_time number(10);
begin
for i in 1..5000 loop
id_table(i):=i;
name_table(i):='Name'||to_char(i);
end loop;
start_time:=dbms_utility.get_time;
--批量綁定的使用開始
forall i in 1..id_table.count
insert into demo values(id_table(i),name_table(i));
--批量綁定的使用結束
end_time:=dbms_utility.get_time;
dbms_output.put_line('總時間'||to_char((end_time-start_time)/100));
end;


2、FORALL語句
說明:當要在PL/SQL中執行批量insert、update、delete操作,可以使用forall語句。
9i前forall語句必須是連續的元素;10g後通過增加indices of子句和values of子句,可以使用不連續的集合元素。
注意:for語句時循環語句,forall不是循環語句。如下面語法,9i只有語法一,10g後新增了語法二、三。


語法一:forall i in lower_bound..upper_bound sql_statement;
其中,i是隱含定義的整數變量(將作爲集合元素下標被引用),lower_bound和upper_bound是集合元素上下界。


語法二:forall i in indices of collection [between lower_bound and upper_bound] sql_statement;
其中,indices of指定只取對應於collection集合元素下標的i值。


語法三:forall i in values of index_collection sql_statement;
其中,values of指定i值從集合變量index_collection中取得。


1)、DML語句上使用批量綁定
說明:使用批量綁定爲數據庫表插入數據時,首先需要給集合元素賦值,然後使用forall語句執行批量綁定插入操作。
declare
type id_table_type id table of number(6) index by binary_integer;
type name_table_type is table of varchar2(10) index by binary_integer;
id_table id_table_type;
name_table name_table_type;
begin
for i in 1..50 loop
id_table(i):=i;
name_table(i):='Name'||to_char(i);
end loop;
forall i in 1..id_table.count
insert into demo values(id_table(i),name_table(i));
update demo set name=name_table(i) where id=id_table(i);
delete from demo where id=id_table(i);
commit;
end;


2)、FORALL語句中使用部分集合連續的元素
說明:上面說到的都是集合的所有元素,forall可以使用部分元素。
declare
type id_table_type id table of number(6) index by binary_integer;
id_table id_table_type;
begin
for i in 1..50 loop
id_table(i):=i;
end loop;
forall i in 8..10
insert into demo values(id_table(i),name_table(i));
commit;
end;


3)、forall語句上使用indices of子句
說明:indices of子句是10g新增,用於跳過集合中的null元素。
declare
type id_table_tyoe is table of number(6);
id_table id_table_type;
begin
id_table:=id_table_type(1,null,3,null,5);
forall i in indicrs of id_table
delete from demo where id=id_table(i);
end;


4)、forall語句上使用values of子句
說明:values of子句是10g新增,用於從其他集合中取得集合下標的值。
declare
type id_table_type is table of demo.id%type;
type name_table_type is table of demo.name%type;
id_table id_table_type;
name_table name_table_type;
type index_pointer_type is table of pls_integer;
index_pointer index_pointer_type;
begin
select * bulk collect into id_table,name_table from demo;
index_pointer:=index_pointer_type(6,8,10);
forall i in values of index_pointer
insert into new_demo_table2 values(id_table(i),name_table(i));
end;
--結果是向表中插入了6 8 10的數據


5)、forall語句上使用SQL%BULK_ROWCOUNT屬性
說明:專門爲forall語句提供的屬性,用於取得執行批量綁定是第i個元素所作用的行數。
declare
type dno_table_type is table of number(3);
dno_table dno_table_type:=dno_table_type(10,20);
begin
forall i in 1..dno_table.count
update emp set sal=sal*1.1 where deptno=dno_table(i);
dbms_output.put_line('第2個元素更新的行數:'||SQL%BULK_ROWCOUNT(2));
end;


3、BULK COLLECT子句
說明:用於取得批量數據,將批量數據存放到PL/SQL集合變量中,只用於select into、fetch into和dml返回子句中。
語法:。。。BULK COLLECT into collection_name[,collection_name]。。。
其中,collection_name指定存放的集合變量名


1)、在select into語句中使用bulk collect
說明:9i前,select into必須且只能返回1行數據,否者拋異常,9i開始通過在elect into使用bulk collect子句可以
一次將select語句的多行結果檢索到集合變量。
declare
type emp_table_type is table of emp%rowtype index by binary_integer;
emp_table emp_table_type;
begin
select * bulk collect into emp_table from emp where deptno=&no;
for i in 1..emp_table.count loop
dnms_output.put_line('emp_table(i).ename');
end;


2)、在DML的返回子句中使用bulk collect子句
說明:爲了取得DML操作所改變的數據,可以使用returning子句;爲了取得DML所作用的多行數據,需要使用bulk collect子句。
declare
type ename_table_type is table of emp.ename%type;
ename_table ename_table_type;
begin
delete from emp where deptnp=&no returning ename bulk collect into ename_table;
dbms_output.put('僱員名:');
for i in 1..ename_table.count loop
dbms_output.put(ename_table(i));
end loop;
end;




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章