SQL> set serveroutput on SQL> declare 2 type tnt_ic01 is table of ic01%rowtype; 3 nt_ic01 tnt_ic01 := tnt_ic01(); 4 n_startTime number; 5 begin 6 n_startTime := dbms_utility.get_time; 7 for rec_ic01 in( select * from ic01 where rownum < 100000 ) loop 8 nt_ic01.extend; 9 nt_ic01( nt_ic01.last ) := rec_ic01; 10 end loop; 11 dbms_output.put_line( 'COUNT: ' || nt_ic01.count ); 12 dbms_output.put_line( 'USED TIEM: ' || ( dbms_utility.get_time - n_startTime ) ); 13 end; 14 / COUNT: 99999 USED TIEM: 255
PL/SQL 过程已成功完成。 |
SQL> declare 2 type tnt_ic01 is table of ic01%rowtype; 3 nt_ic01 tnt_ic01; 4 n_startTime number; 5 begin 6 n_startTime := dbms_utility.get_time; 7 select * 8 bulk collect into nt_ic01 9 from ic01 10 where rownum < 100000; 11 dbms_output.put_line( 'COUNT: ' || nt_ic01.count ); 12 dbms_output.put_line( 'USED TIEM: ' || ( dbms_utility.get_time - n_startTime ) ); 13 end; 14 / COUNT: 99999 USED TIEM: 159
PL/SQL 过程已成功完成。 |
SQL> declare 2 type tnt_ic01 is table of ic01%rowtype; 3 nt_ic01 tnt_ic01; 4 rec_ic01 ic01%rowtype; 5 begin 6 --1. normal select, can cause no_data_found 7 begin 8 select * 9 into rec_ic01 10 from ic01 11 where 1 = 0; 12 exception 13 when no_data_found then 14 dbms_output.put_line( 'error1: no_data_found exception accured!' ); 15 end; 16 17 --2. bulk collect, won't cause no_data_found 18 select * 19 bulk collect into nt_ic01 20 from ic01 21 where 1 = 0; 22 if nt_ic01.count = 0 then 23 dbms_output.put_line( 'error2: There is no data in nt_ic01.' ); 24 end if; 25 end; 26 / error1: no_data_found exception accured! error2: There is no data in nt_ic01.
PL/SQL 过程已成功完成。 |
-- 1. fetch collect into SQL> declare 2 cursor cur_ic01 is 3 select * 4 from ic01 5 where rownum < 10; 6 7 type tnt_ic01 is table of cur_ic01%rowtype; 8 nt_ic01 tnt_ic01; 9 begin 10 open cur_ic01; 11 fetch cur_ic01 bulk collect into nt_ic01; 12 close cur_ic01; 13 dbms_output.put_line( 'COUNT: ' || nt_ic01.count ); 14 end; 15 / COUNT: 9
PL/SQL 过程已成功完成。
-- 2. returning into SQL> select * from test_return;
AAC001 AAC003
SQL> declare
PL/SQL 过程已成功完成。
SQL> select * from test_return; AAC001 AAC003 SQL> |
SQL> declare 2 cursor cur_ic01 is 3 select * 4 from ic01 5 where rownum < 10; 6 7 type tnt_ic01 is table of cur_ic01%rowtype index by pls_integer; 8 nt_ic01 tnt_ic01; 9 begin 10 open cur_ic01; 11 fetch cur_ic01 bulk collect into nt_ic01; 12 close cur_ic01; 13 dbms_output.put_line( 'COUNT: ' || nt_ic01.count ); 14 end; 15 / COUNT: 9
PL/SQL 过程已成功完成。 |
BULK COLLECT 生成的集合,下表是默认从1开始的数字,步进为1,所以联合数组的索引,不能使用 varchar2 类型。如果你不小心使用了 varchar2 类型作为联合数组的索引,就会出现下面的错误:
SQL> select * from v$version; BANNER SQL> declare 2 type tnt_ic01 is table of ic01%rowtype; 3 nt_ic01 tnt_ic01; 4 5 v_sql_cursor varchar2(1000); 6 begin 7 v_sql_cursor := 'select * from ic01 where rownum < 100000'; 8 execute immediate v_sql_cursor bulk collect into nt_ic01; 9 dbms_output.put_line( 'COUNT: ' || nt_ic01.count ); 10 end; 11 / COUNT: 99999
PL/SQL 过程已成功完成。
SQL> |
ERROR 位于第 11 行: ORA-06550: 第 11 行, 第 36 列: PLS-00657: 实施约束: 不支持带有 VARCHAR2 关键字的关联性数组的批 SQL。 |
5. VARRAY 数组中使用 BULK COLLECT
而对于 VARRAY 数组,BULK COLLECT 也适用,不过定义时,其长度必须得大于或等于结果集的长度:
SQL> declare 2 cursor cur_ic01 is 3 select * 4 from ic01 5 where rownum < 10; 6 7 type tnt_ic01 is varray(9) of ic01%rowtype; 8 nt_ic01 tnt_ic01; 9 begin 10 open cur_ic01; 11 fetch cur_ic01 bulk collect into nt_ic01; 12 close cur_ic01; 13 dbms_output.put_line( 'COUNT: ' || nt_ic01.count ); 14 end; 15 / COUNT: 9
PL/SQL 过程已成功完成。 |
如果 VARRAY 数组长度定义得过小,则会提示错误:
SQL> declare 2 cursor cur_ic01 is 3 select * 4 from ic01 5 where rownum < 10; 6 7 type tnt_ic01 is varray(8) of ic01%rowtype; 8 nt_ic01 tnt_ic01; 9 begin 10 open cur_ic01; 11 fetch cur_ic01 bulk collect into nt_ic01; 12 close cur_ic01; 13 dbms_output.put_line( 'COUNT: ' || nt_ic01.count ); 14 end; 15 / declare * ERROR 位于第 1 行: ORA-22165: 指定的索引 [9] 必须介于 [1] 到 [8] 之间 ORA-06512: 在 line 11 |
如果 VARRAY 数组长度定义得过大,没什么影响,而且也不会占用多余的内存空间:
SQL> declare 2 cursor cur_ic01 is 3 select * 4 from ic01 5 where rownum < 10; 6 7 type tnt_ic01 is varray(10) of ic01%rowtype; 8 nt_ic01 tnt_ic01; 9 begin 10 open cur_ic01; 11 fetch cur_ic01 bulk collect into nt_ic01; 12 close cur_ic01; 13 dbms_output.put_line( 'COUNT: ' || nt_ic01.count ); 14 dbms_output.put_line( 'LIMIT: ' || nt_ic01.limit ); 15 end; 16 / COUNT: 9 LIMIT: 10
PL/SQL 过程已成功完成。 |
不过推荐首选联合数组,或是嵌套表,在这里虽然可以使用 VARRAY 数组,但显然是不太合适的,就像steven 所介绍的那样。
6. 动态 SQL 中使用 BULK COLLECT