ORACLE集合学习总结

index-by table类型,这个类型只能在过程定义,因此不能在返回函数中使用。

 

 

declare

  -- 定义

 

 type  t_a  is table  of  number(4) index by pls_integer;

 a   t_a;

 

   type  t_b  is table  of  number(10,2) index by varchar2(20);

 b   t_b;

begin

 

--赋值

 

a(1) := 123;

a(2) := 456;

--a(3) := 456;

a(4) := 888;

 

b('CHINA') :=  13000;

 

b('AMERCIAN') := 300000;

 --输出

 fori in 1..a.count loop

 --ifa(i).exists then    --错误的写法

 ifa.exists(i) then  --正确的写法

 dbms_output.put_line(a(i));

 endif;

 endloop;

 

 

 dbms_output.put_line('------------------------------------------------------');

 

 ifb.exists('CHINA') then  --正确的写法

 dbms_output.put_line(b('CHINA') );

 endif;

 

end;

 

oracle数据库提供了类似的一种集合,这个集合可以在过程中定义,也可以在过程外定义,其方法与pl/sql table类型的集合相似。

DECLARE

TYPE NumList IS TABLE OF NUMBER;

--这里没有index by

n NumList := NumList(1,3,5,7);

---需要初始化

counter INTEGER;

BEGIN

n.DELETE(2); --删除第二条记录

 

counter := n.FIRST; --实际上是1

WHILE counter IS NOT NULL

LOOP

DBMS_OUTPUT.PUT_LINE

('Counting up: Element #' || counter || ' =' || n(counter));

counter := n.NEXT(counter);

END LOOP;

-- Run the same loop in reverse order.

counter := n.LAST;

WHILE counter IS NOT NULL

LOOP

DBMS_OUTPUT.PUT_LINE

('Counting down: Element #' || counter || '= ' || n(counter));

counter := n.PRIOR(counter);

END LOOP;

END;

 

还有一种集合类型 varry,但是运用很少。

 

集合的定义与方法很简单,了解其他编程语言的数组,很容易理解这些概念。

然而oracle的集合却是oracle提高效率,灵活实现功能的一种重要方法。

Oracle提高了表函数能够将一个集合映射为一个表,这个表可以与其他数据集合一些使用(仅限于select,不能通过DML修改集合类型。)

 

集合占用了内存,了解集合占用内存情况很有必要

 

集合内存释放情况

 

win xp  oracle11g

DECLARE

TYPEdnames_tab IS TABLE OF char(2000);

 

dept_names dnames_tab := dnames_tab();

empty_set dnames_tab;

BEGIN

 

select rownum||'**' bulk collect into dept_names from dual connect by level<=100000;

 

ifdept_names is not null then

DBMS_OUTPUT.PUT_LINE(dept_names.count);

else

DBMS_OUTPUT.PUT_LINE('null');

end if;

 

dept_names := empty_set;

 

ifdept_names is not null then

DBMS_OUTPUT.PUT_LINE(dept_names.count);

else

DBMS_OUTPUT.PUT_LINE('null');

end if;

dbms_lock.sleep(10);

END;

 

运行上面的程序,观察系统内存比变化情况,发现只有程序运行时,使用内存在增加,dept_names :=empty_set;

后内存并没有立即释放,而是等到增个程序end的时候,才被释放。

说明:oracle的官方文档在这方面的介绍有一些问题:

oracle的官方文档说,一个集合trim后,会释放其占用的内存空间,但是我的测试结果并不支持这样的说法。

 

 

因此在程序中尽量避免大集合长期霸占内存,或者大集合多次拷贝

 

集合方法

集合的一些常用方法

窗体顶端

方法窗体底端

描述

使用限制

Count

返回集合中元素的个数

Delete

删除集合中所有元素

Delete(x)

删除元素下标为x的元素,如果x为null,则集合保持不变

对varray非法

Delete(x,y)

删除元素下标从x到y的元素,如果x>y则集合保持不变

对varray非法

Exists(x)

如果集合元素x已经初始化,则返回ture否则返回false

Extend

在集合末尾添加一个元素

对index_by非法

Extend(x)

在集合末尾添加x个元素

对index_by非法

Extend(x,n)

在集合末尾添加元素n的x个副本

对index_by非法

First

返回集合第一个元素的下标号,对于varray集合始终返回1

Last

返回集合中最后一个元素的下标号,对于varray集合返回值始终等于count

Limit

返回varry集合的最大元素个数,对于嵌套表和index_by始终为null

Index_by和嵌套表无效

Next()

返回元素x之后紧挨着他的元素的值,如果该元素是最后一个元素,则返回null

Prior()

返回集合中元素在x之前紧挨着他的元素的值,如果该元素是第一个元素,则返回null

Trim

从集合末端开始删除一个元素

Trim(x)

从集合末端开始删除x个元素

  窗体底端

 

上面提到的很多方法,在实际开发中较少使用到,无须记住它们。

 

似是而非的问题(trim|delete|count|first..last)

 

DECLARE

TYPE nested_typ IS TABLE OF NUMBER;

  nt1nested_typ := nested_typ(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);

  BEGIN

 

   dbms_output.put_line('nt1.count=' || nt1.count);

 

   for i in 1 .. nt1.count loop

     if nt1(i) is not null then

       dbms_output.put_line(nt1(i));

     end if;

   end loop;

    dbms_output.put_line('************************************');

   nt1.delete(4);

   nt1.delete(6);

   nt1.delete(8);

 

   dbms_output.put_line('nt1.count=' || nt1.count);

   

   for i in 1 .. nt1.count loop

     if nt1.exists(i) then

       dbms_output.put_line(nt1(i));

     else

        dbms_output.put_line('位置在 但是没有'); 

     end if;

   end loop;

    dbms_output.put_line('************************************');  

   for i in nt1.first .. nt1.last loop

     if nt1.exists(i) then

       dbms_output.put_line(nt1(i));

     else

        dbms_output.put_line('位置在 但是没有');         

     end if;

   end loop;

     dbms_output.put_line('************************************');        

 end;

 

输出结果

nt1.count=12

1

2

3

4

5

6

7

8

9

10

11

12

************************************

nt1.count=9

1

2

3

位置在 但是没有

5

位置在 但是没有

7

位置在 但是没有

9

************************************

1

2

3

位置在 但是没有

5

位置在 但是没有

7

位置在 但是没有

9

10

11

12

************************************

看到如果集合还是变得稀疏,使用count 就开始产生疑义,最好采用first last。

 

 

 

单字段集合

declare

  --声明一个集合对象typ_number 用于存放number(10,2)的数组

 type typ_number is table of number(10,2);

  --声明一个对象typ_number的实例并初始化

 sal  typ_number := typ_number();

 

 i_rowcounts  integer;

begin

  --扩展一个组员

 sal.extend(1);

  --赋予一个组员值

 sal(sal.last) :=100.11;

 

  --利用循环赋值

  fori in 1..100 loop

   sal.extend(1);

   sal(sal.last) := sqrt(i);

  endloop;

  --输出

 dbms_output.put_line(sal.count);

 

  sal.extend(100);

  for i in 100..200 loop

   sal(i+1) := sqrt(i);

  endloop;

  dbms_output.put_line(sal(200));

  

   --将select 的结果装入数组

  

  select  count(*) intoi_rowcounts  from scott.emp;

  dbms_output.put_line(i_rowcounts);

    

   ifi_rowcounts>0 then

   select sal s  bulk collect intosal from scott.emp;

  end if;

  

  for  k in 1.. sal.count loop

   dbms_output.put_line(sal(k));

  end loop;

   --请问现在集合sal有多少个元素?

   --注意 如果采用bulk collect into 则这个集合从新初始化了

 

   --动态语句sql的集合赋值

   sal.delete;

  dbms_output.put_line(sal.count);

  

  sql_stmt := 'select sal from scott.emp';

  execute immediate sql_stmt  bulk collectinto sal;

   dbms_output.put_line(sal.count); 

end;

 

尽管可以用游标来赋值,但是我们还是力主用collect bulk into来赋值。

 

多个字段的集合的赋值方法

定义一个多字段的对象

create type myScalarType as object( x int, y date, z varchar2(30));

定义一个基于该对象的集合

create type myArrayType as table of myScalarType;

 

 

declare

   l_data myArrayType :=myArrayType();

begin

   l_data.extend;

   l_data(1).x := 42;

   l_data(1).y := sysdate;

   l_data(1).z := 'hello world';

   l_data.extend;

   l_data(2) := myScalarType( 1, sysdate, 'x' );

end;

 

如果在扩展后,l_data(l_data.count).x:= 42;操作成功

但是l_data(l_data.count).y:= sysdate-100; 却出现了错误

或者直接l_data(l_data.count).y:= sysdate-100;也出现了错误

 

正确的做法是

l_data(1):=myScalarType(1,sysdate,'ggg');

或者

l_data(1):=myScalarType(null,null,null);

再赋值

declare

   l_data myArrayType := myArrayType();

begin

   l_data.extend;

   l_data(1):=myScalarType(1,sysdate,'ggg');

   dbms_output.put_line(l_data(1).y);

end;

 

但是对于本地集合plsql index by (sparse) table

DECLARE

 TYPE r_prods is RECORD (Prod_no number(1),

                        DAY_IN_WEEK  number(1),

                        BRANCH_NO     NUMBER(1),

                         QTY           NUMBER(4));

 

 TYPE t_prods IS TABLE OF r_prods INDEX BY BINARY_INTEGER;

 v_Prods t_prods;

BEGIN

   v_Prods(111).prod_no :=1;

   v_Prods(111).day_in_week :=1;

   v_Prods(111).branch_no :=1;

   v_Prods(111).qty:=300;

   v_Prods(121).prod_no :=1;

   v_Prods(121).day_in_week :=2;

   v_Prods(121).branch_no :=1;

   v_Prods(121).qty:=400;

  -- dbms_output.put_line(l_data(1).y);

end;

却成功

 

 

Limit

 

Limit是9i以后版本引进的

 

注意点:

1、limit 的参数不是越大越好

2、退出的写法与位置

 

注意游标退出的判断以及位置

 

DECLARE

TYPE numtab IS TABLEOF NUMBER INDEX BY PLS_INTEGER;

CURSOR c1 IS SELECT hr.employee_idFROM employees WHERE department_id = 80;

empids numtab;

rows PLS_INTEGER :=10;

BEGIN

OPEN c1;

LOOP -- the following statement fetches 10 rows or less ineach iteration

FETCH c1 BULKCOLLECT INTO empids LIMIT rows;

EXIT WHENempids.COUNT = 0;

-- EXIT WHENc1%NOTFOUND; --不正确, 这样写可能或略部分数据

DBMS_OUTPUT.PUT_LINE('-------Results from Each Bulk Fetch --------');

FOR i IN 1..empids.COUNT LOOP

DBMS_OUTPUT.PUT_LINE('Employee Id: ' || empids(i));

END LOOP;

END LOOP;

CLOSE c1;

END;

 

 

 

 

 

 

 

 

 

 

 

 

集合的运算以及集合与表运算

 

drop type type_emp

create or replace type emp_t as object

(

empno  number(4,0),

ename  varchar2(20),

sal   number(16,2)

)

 

 

测试

selectemp_t(empno,ename,sal) from emp;

 

drop type emp_t

create type table_emp is table of emp_t

 

declare

  i integer;

  e table_emp;

  e1 table_emp;

  v_sal number(16,0);

 

  type c_sal is table of number(10,2);

  v_c c_sal;

begin

  select emp_t(empno,ename,sal) bulk collect into e from emp;

  dbms_output.put_line(e.count);

 

  for i in 1..e.count loop

  dbms_output.put_line(e(i).empno||'      '||e(i).sal);

  end loop;

 

  /*

  for i in1..e.count loop

  e(i).sal:=(selectsum(sal) from emp where empno=e(i).empno);

  end loop;

 */

 

  for i in 1..e.count loop

  select sal into v_sal from emp where empno=e(i).empno;

  e(i).sal:=e(i).sal+v_sal;

  end loop;

 

  for i in 1..e.count loop

  dbms_output.put_line(e(i).empno||'      '||e(i).sal);

  end loop;

 

  select sal bulk collect into v_c from emp;

 

  for i in 1..e.count loop

  e(i).sal:=v_c(i);

  end loop;

 

  for i in 1..e.count loop

  dbms_output.put_line(e(i).empno||'      '||e(i).sal);

  end loop;

 

  select

  emp_t(empno,ename,sal) bulk collect into e1

  from table(e);

 

  dbms_output.put_line('print e1'); 

 

  for i in 1..e1.count loop

  dbms_output.put_line(e1(i).empno||'      '||e1(i).sal);

  end loop; 

 

  e1.delete;

 

  select

  emp_t(a.empno,a.ename,a.sal+b.sal)bulk collect into e1

  from table(e)a, emp b

  where a.empno=b.empno;

 

  dbms_output.put_line('print e1 withtable'); 

 

  for i in 1..e1.count loop

  dbms_output.put_line(e1(i).empno||'      '||e1(i).sal);

  end loop;

 

--对于表,我们可以

/*

update   emp a

set a.sal= 1+(select sal from emp wherea.empno=emp.empno);

*/

 

 

--update   table(e)a

--set a.sal= 1+(select sal from emp wherea.empno=emp.empno);

--但是对于集合 则 

--ora-00903错误 表名无效

 

for i in 1..e.count loop

for j in 1..e1.count loop

if e1(j).empno=e(i).empnothen

e(i).sal:=nvl(e(i).sal,0)+nvl(e1(j).sal,0);

end if;

end loop;

end loop;

 

dbms_output.put_line('col operate with other col');

  for i in 1..e1.count loop

  dbms_output.put_line(e1(i).empno||'      '||e1(i).sal);

  end loop;

end;

 

 

集合排序与拷贝

declare

  i integer;

  e table_emp;

  e_order table_emp;

  e1 table_emp;

  v_sal number(16,0);

  type c_sal is table of number(10,2);

  v_c c_sal;

 

begin

  select emp_t(empno,ename,sal) bulk collect into e from emp;

  dbms_output.put_line(e.count);

 

  for i in 1..e.count loop

  dbms_output.put_line(e(i).empno||'      '||e(i).sal);

  end loop;

 

  select count(*) into i from table(e);

  dbms_output.put_line('i from e '||i);

 

  select emp_t(empno,ename,sal)

  bulk collect into e_order

  from table(e) order by sal;

  dbms_output.put_line('print e_order'); 

  for i in 1..e.count loop

 dbms_output.put_line(e_order(i).empno||'     '||e_order(i).sal);

  end loop;

end;

 

或者常用方法进行排序,这样可以节省内存空间

declare

 -- Local variables here

 type table_sal is table of scott.emp.sal%type;

 c_sal table_sal;

 v_sal  scott.emp.sal%type :=0;

 point integer;

begin

select sal bulk collect intoc_sal from emp;

 

for i in 1..c_sal.count loop

 dbms_output.put_line(c_sal(i));

end loop;

 

 dbms_output.put_line('----------------------------------');

for i in 2..c_sal.count loop

for i in 2..c_sal.count loop

if c_sal(i) > c_sal(i-1) then

 v_sal := c_sal(i-1);

 c_sal(i-1) :=c_sal(i);

 c_sal(i) := v_sal;

end if ;

end loop;

end loop;

 

for i in 1..c_sal.count loop

 dbms_output.put_line(c_sal(i));

 end loop;

end;

 

输出

-----------------------------------------------------------

800
1600
1250
2975
1250
2850
2450
3000
5000
1500
1100
950
3000
1300
----------------------------------
5000
3000
3000
2975
2850
2450
1600
1500
1300
1250
1250
1100
950
800

 

如果一个集合中的元素被删除,调用这个元素则会出错

declare

 i integer;

 e table_emp;

 e1 table_emp;

 e2 table_emp; 

 v_sal number(16,0);

 

 type c_sal is table of number(10,2);

 v_c c_sal;

begin

 select emp_t(empno,ename,sal) bulk collect into e from emp;

 dbms_output.put_line(e.count);

 

 for i in 1..e.count loop

 dbms_output.put_line(nvl(e(i).empno,0)||'      '||nvl(e(i).sal,0));

 end loop;

e.delete(1);

--e.trim(13);

 

--集合第一条数据被删除

--结果集合的条数从3变成2

--但是 如果想输出集合 则出现错误

 

 -- for i in 1..e.count loop

 --dbms_output.put_line(nvl(e1(i).empno,0)||'   '||nvl(e1(i).sal,0));

 --end loop;

--错误

 

--解决方法 1  作以下判断

 for i in 1..e.count loop

 if e1.exists(i) then

 dbms_output.put_line(nvl(e1(i).empno,0)||'     '||nvl(e1(i).sal,0));

 end if;

 end loop;

 

 

--解决方法2  将删除后的集合 放到一个新的集合中

 

select emp_t(empno,ename,sal)bulk collect into e1 from table(e);

 dbms_output.put_line(e1.count);

 

 for i in 1..e.count loop

 dbms_output.put_line(nvl(e1(i).empno,0)||'      '||nvl(e1(i).sal,0));

 end loop;

end;

 

DECLARE

 TYPE NumList IS TABLE OF NUMBER;

 n NumList := NumList(10,20,30,40,50,60,70,80,90,100);

 

 BEGIN

 dbms_output.put_line(n.count);

 

 n.DELETE(2); -- deletes element 2

 dbms_output.put_line(n.count);

 

 for i in 1..n.count loop

 dbms_output.put_line(n(i));

 end loop;

 

 end;

 

第 1 行出现错误:

ORA-01403: 未找到任何数据

ORA-06512: 在 line 12

 

修改

for i in 1..n.count loop
 if n.exists(i) then
 dbms_output.put_line(n(i));
 end if;
 end loop;

 

 

集合运算

IN | not IN

 

 

DECLARE

 TYPE nested_typ IS TABLE OF NUMBER;

 nt1  nested_typ := nested_typ(1,2, 3);

 nt2  nested_typ := nested_typ(1,2, 3, 4);

 flag boolean := true;

 p    integer := 0;

BEGIN

 

 if nt1 IN (nt2) then

   dbms_output.put_line('true');

 else

   dbms_output.put_line('false');

 end if;

 

 --输出 为flase  这不是我们所需要的结果

 

 for i in 1 .. nt1.count loop

   for j in 1 .. nt2.count loop

     if nt1(i) = nt2(j) then

        p := p + 1;

     end if;

   end loop;

   if p > i then

     p := i;

   end if;

   if p < i then

     flag := false;

   end if;

   exit when p < i;

 end loop;

 

 if flag = true then

   dbms_output.put_line('true');

 else

   dbms_output.put_line('false');

 end if;

 --这是我们所需要的结果

END;

可以将上述过程编写成函数。

 

Distinct

DECLARE

 TYPE nested_typ IS TABLE OF NUMBER;

 nt1  nested_typ :=nested_typ(100,1, 2, 3, 6,6,6, 19,9,7,11,3, 2, 12,1,14, 3,11,1,11,1,13,109);

 collect_count integer;

BEGIN

 

 dbms_output.put_line('nt1.count=' || nt1.count);

 collect_count := nt1.count;

 for i in nt1.first .. nt1.last loop

   for j in nt1.first .. nt1.last loop

   --注意 不能写成  1.. nt1.count

     if nt1.exists(i) and nt1.exists(j) then

        if i <> j and nt1(i) = nt1(j)then

          nt1.delete(j);

        end if;

     end if;

   end loop;

 end loop;

 

 dbms_output.put_line('nt1.count=' || nt1.count);

 for i in nt1.first .. nt1.last loop

   if nt1.exists(i) then

     dbms_output.put_line(nt1(i));

   end if;

 end loop;

END;

-------------------------------------------

100
1
2
3
6
19
9
7
11
12
14
13
109

 

 

union all

思想 找出较少元素的结合,通过loop将元素增加到较多元素的集合中,程序省略

 

union

union all + distinct

或者自己重新编写程序

 

intersect

自己重新编写程序

 

intersect

自己重新编写程序

 

 

利用oracle的集合运算符(unionall | union | minus | intersect) 对集合进行集合运算

利用表函数将集合转化为可以select的表,在做集合运算

好处是简化程序 弊端为分配一个新的内存

 

create TYPE nested_typ IS TABLE OF NUMBER;

 

DECLARE

nt1 nested_typ := nested_typ(1,2,3,5);

nt2 nested_typ := nested_typ(3,2,1,4);

nt3 nested_typ := nested_typ(2,3,1,3);

nt4 nested_typ := nested_typ(1,2,4);

nt5 nested_typ := nested_typ();

BEGIN

 

for i in 1..nt1.count loop

  for j in 1..nt2.count loop

  if nt1(i)=nt2(j) then

   dbms_output.put_line(nt1(i));

   end if;

  end loop;

end loop;

 

 

select a

bulk collect into nt5

from

(

select column_value a from table(nt1)

union all

select column_value a from table(nt2)

);

 

 

for i in 1..nt5.count loop

   dbms_output.put_line(nt5(i));

end loop;

 

END;

 

 

负集

create TYPE NumList IS TABLE OF NUMBER;

 

DECLARE

n2 NumList:= NumList(10,20,35,90);

n1NumList:= NumList(10,20,30,40,50,60,70,80,90,100);

n3 NumList := NumList();

BEGIN

 

select a

bulk collect into n3

from

(

select column_value a fromtable(n1)

minus

select column_value a fromtable(n2)

);

 

for i in 1..n3.count loop

dbms_output.put_line(n3(i));

end loop;

end;

 

 

集合的运算

注意集合类型一定在外定义

不能在程序内部定义

create or replace TYPE NumList IS TABLE OF integer;

 

DECLARE

不能在程序内部定义

--TYPE NumList IS TABLE OF NUMBER;

n NumList := NumList(10,20,35);

n1 NumList:= NumList(10,20,30,40,50,60,70,80,90,100);

n3 NumList;

i integer;

BEGIN

 

 

selectNumList(a) bulk_collect into n3

from

(

selectcolumn_value a from table(n)

minus

selectcolumn_value a from table(n1)

);

 

for i in 1..n3.count loop

dbms_output.put_line(n3(i));

end loop;

end;

 

集合与表的联合运算

 

declare

--不能在程序内部定义

--TYPE NumList IS TABLE OF NUMBER;

n NumList := NumList(10,20,35);

n1 NumList:= NumList(10,20,30,40,50,60,70,80,90,100);

n3 NumList;

i integer;

BEGIN

 

select a.empno bulk collect into n3  from

emp a,table(n) b

wherea.deptno=b.column_value;

 

for i in 1..n3.count loop

dbms_output.put_line(n3(i));

end loop;

end;

 

以上我们看到集合的方法以及自定义的集合运算方法,我们也了解到了从数据库的结果集批量取数到集合中的方法。

 

下面介绍更重要的集合数据的物化问题,就是将集合数据dml表中。

FORALL技术

 

先看一个基本的例子

 

create table TARGET_ALL_OBJECT
(
  OWNER          VARCHAR2(30),
  OBJECT_NAME    VARCHAR2(30),
  SUBOBJECT_NAME VARCHAR2(30),
  OBJECT_ID      NUMBER,
  DATA_OBJECT_ID NUMBER,
  OBJECT_TYPE    VARCHAR2(19),
  CREATED        DATE,
  LAST_DDL_TIME  DATE,
  TIMESTAMP      VARCHAR2(19),
  STATUS         VARCHAR2(7),
  TEMPORARY      VARCHAR2(1),
  GENERATED      VARCHAR2(1),
  SECONDARY      VARCHAR2(1),
  NAMESPACE      NUMBER,
  EDITION_NAME   VARCHAR2(30)
)

 

declare

          cursor c1 is select * from cur_all_object slow_by_slow;

          cursor c2 is select * from cur_all_object  bulk_collect;

 

          type array is table of c1%rowtype index by binary_integer;

          l_array array;

           l_row  c1%rowtype;

          start_time int;

  begin

         start_time := dbms_utility.get_time;

          open c1;

          loop

                   fetch c1 into l_row;

                   exit when c1%notfound;

                   insert intotarget_all_object(object_id) values(l_row.object_id);

          end loop;

          close c1;

        dbms_output.put_line(( dbms_utility.get_time-start_time)/100);

        commit;

        

        execute immediate 'truncate table target_all_object ';

 

         start_time := dbms_utility.get_time;

          open c2;

          loop

                   fetch c2 bulk collect intol_array limit 10000;

                   -- process rows here --

                   exit when c2%notfound;

                  

                   for m in 1..l_array.countloop

                   insert intotarget_all_object(object_id)  values(l_array(m).object_id);

                   end loop;

                  

          end loop;

          close c2;

          dbms_output.put_line(( dbms_utility.get_time-start_time)/100);

          commit;

          execute immediate 'truncate table target_all_object '; 

                  

        start_time := dbms_utility.get_time;

          open c2;

          loop

                  fetch c2 bulk collectinto l_array limit 10000;

                   -- process rows here --

                   exit when c2%notfound;

                  

                   forall m in 1..l_array.count

                   insert into target_all_object(object_id)  values (l_array(m).object_id);

                  

          end loop;

          close c2;

          dbms_output.put_line(( dbms_utility.get_time-start_time)/100);

          commit;

          execute immediate 'truncate table target_all_object ';         

  end;

--------

4.22
2.93
0.34

 

limit=100

--------

4.23
2.86
0.36

 

插入全表的数据

 

 

declare

           cursor c1 is select * fromcur_all_object slow_by_slow;

           cursor c2 is select * fromcur_all_object  bulk_collect;

 

           type array is table of tiwen.target_all_object%rowtype  index by binary_integer;

           l_array array;

           l_row   tiwen.target_all_object%rowtype;

           start_time int;

   begin

          start_time := dbms_utility.get_time;

           open c1;

           loop

                   fetch c1 into l_row;

                   exit when c1%notfound;

                   insert into target_all_object  values  l_row;

           end loop;

           close c1;

         dbms_output.put_line((dbms_utility.get_time-start_time)/100);

         commit;

        

         execute immediate 'truncate tabletarget_all_object ';

 

          start_time := dbms_utility.get_time;

           open c2;

           loop

                   fetch c2 bulk collect intol_array limit 200;

                   -- process rows here --

                   exit when c2%notfound;

                  

                   for m in 1..l_array.countloop

                   insert into target_all_object  values l_array(m);

                   end loop;

                  

           end loop;

           close c2;

           dbms_output.put_line((dbms_utility.get_time-start_time)/100);

           commit;

           execute immediate 'truncate tabletarget_all_object '; 

                  

         start_time := dbms_utility.get_time;

           open c2;

           loop

                   fetch c2 bulk collect into l_array limit10000;

                   -- process rows here --

                   exit when c2%notfound;

                  

                   forall m in 1..l_array.count

                   insert into target_all_object valuesl_array(m);

                  

           end loop;

           close c2;

           dbms_output.put_line((dbms_utility.get_time-start_time)/100);

           commit;

           execute immediate 'truncate tabletarget_all_object ';         

   end;

 

 

或者

declare

          cursor c1 is select * from cur_all_object slow_by_slow;

          cursor c2 is select * from cur_all_object  bulk_collect;

 

           type array is table of c1%rowtypeindex by binary_integer;

           l_array array;

           l_row   c1%rowtype;

          start_time int;

  begin

         start_time := dbms_utility.get_time;

          open c1;

          loop

                   fetch c1 into l_row;

                   exit when c1%notfound;

                   insert into target_all_object  values l_row;

          end loop;

          close c1;

        dbms_output.put_line(( dbms_utility.get_time-start_time)/100);

        commit;

        

        execute immediate 'truncate table target_all_object ';

 

         start_time := dbms_utility.get_time;

          open c2;

          loop

                   fetch c2 bulk collect intol_array limit 10000;

                   -- process rows here --

                   exit when c2%notfound;

                  

                   for m in 1..l_array.countloop

                   insert into target_all_object  values l_array(m);

                   end loop;

                  

          end loop;

          close c2;

          dbms_output.put_line(( dbms_utility.get_time-start_time)/100);

          commit;

          execute immediate 'truncate table target_all_object '; 

                  

        start_time := dbms_utility.get_time;

          open c2;

          loop

                   fetch c2 bulk collect intol_array limit 10000;

                   -- process rows here --

                   exit when c2%notfound;

                  

                   forall m in 1..l_array.count

                   insert into target_all_object  values l_array(m);

                  

          end loop;

          close c2;

          dbms_output.put_line(( dbms_utility.get_time-start_time)/100);

          commit;

          execute immediate 'truncate table target_all_object ';         

  end;

 

 

看到 FORALL 极大地提高了效率,与取数一样,forall避免了工作引擎之间的切换。

 

注意写法上的差别

 

                   for m in 1..l_array.countloop

                   insert intotarget_all_object  values l_array(m);

                   end loop;

 

                   forall m in 1..l_array.count

                   insert into target_all_object  values l_array(m);

 

FORALL后面直接跟上dml语句,中间不能有其他如判断过程。如

                   forall m in 1..l_array.count

                    if mod(object_id,2)=1 then

                       insert into target_all_object  values l_array(m);

                   end if;

 

 

结束时候 没有END LOOP这句话

 

                   forall m in 1..l_array.count

                   insert intotarget_all_object  values l_array(m);

不支持稀疏集合

declare

          cursor c1 is select * from cur_all_object slow_by_slow;

          cursor c2 is select * from cur_all_object  bulk_collect;

 

          type array is table of c1%rowtype index by binary_integer;

          l_array array;

          l_row   c1%rowtype;

          start_time int;

  begin                  

        start_time := dbms_utility.get_time;

          open c2;

          loop

                   fetch c2 bulk collect intol_array limit 10000;

                   -- process rows here --

                   exit when c2%notfound;

                  

                   l_array.delete(10);

                   forall m in 1..l_array.count

                   insert intotarget_all_object  values l_array(m);

                  

          end loop;

          close c2;

          dbms_output.put_line(( dbms_utility.get_time-start_time)/100);

          commit;

          execute immediate 'truncate table target_all_object ';         

  end;

 

ORA-22160: 下标 [10] 中的元素不存在

ORA-06512: 在 line 18

 

为解决这个问题,在oracle10个中提供了新的语法

 

declare

          cursor c1 is select * from cur_all_object slow_by_slow;

          cursor c2 is select * from cur_all_object  bulk_collect;

 

          type array is table of c1%rowtype index by binary_integer;

          l_array array;

          l_row   c1%rowtype;

          start_time int;

  begin                  

        start_time := dbms_utility.get_time;

          open c2;

          loop

                   fetch c2 bulk collect intol_array limit 10000;

                   -- process rows here --

                   exit when c2%notfound;

                  

                   l_array.delete(10);

                   forall m in INDICES OFl_array

                   insert intotarget_all_object  values l_array(m);

                 

          end loop;

          close c2;

          dbms_output.put_line(( dbms_utility.get_time-start_time)/100);

          commit;

          execute immediate 'truncate table target_all_object ';         

  end;

 

如果只想插入新数据的一部分 如第2,7,10个,oracle 10g中又提供了 in value的语法

 

declare

          cursor c1 is select * from cur_all_object slow_by_slow;

          cursor c2 is select * from cur_all_object  bulk_collect;

 

          type array is table of c1%rowtype index by binary_integer;

          l_array array;

          l_row   c1%rowtype;

          start_time int;

          

          TYPE aat_id IS TABLE OF PLS_INTEGERINDEX BY PLS_INTEGER;

          legal_ids aat_id;

  begin                  

        start_time := dbms_utility.get_time;

          open c2;

          loop

                   fetch c2 bulk collect intol_array limit 10000;

                   -- process rows here --

                   exit when c2%notfound;

                  

                   legal_ids(1) := 2;

                   legal_ids(2) := 7;

                   legal_ids(3) := 10;

                  

                   forall m IN VALUES OFlegal_ids

                   insert intotarget_all_object  values l_array(m);

                 

                  

          end loop;

          close c2;

          dbms_output.put_line(( dbms_utility.get_time-start_time)/100);

          commit;

          execute immediate 'truncate table target_all_object ';         

  end;

 

 

FORALL是oracle的一个很重要的技术选项,上面只是介绍了 FORALL insert操作,FORALL支持oracle的所有DML操作。

 

FORALL update

在我们讲到用一个数据集更新另一个数据集进行update操作的时候,update隐含着一个规则,即用于更新的数据源在关联条件上一定是唯一的。但是很多情况下,这个隐含的规则并不满足。

 

create table source_update

(

 seq    int,

 id     int,

 name  varchar2(10)

)

 

SEQ

ID

NAME

1

10

aaaa

2

20

bbbb

3

10

cccc

4

30

pppp

 

 

create table target_update

(

id     int,

 name  varchar2(10)

)

ID

NAME

10

mmmmmmmm

20

dddd

30

sss

40

aaavvv

 

merge into target_update a

using (select * from source_update)  b

on (a.id=b.id)

when matched then

update set name=b.name

 

ORA-30926: 无法在源表中获得一组稳定的行

 

可以取得最新的更新数据源

merge into target_update a
using (
select * from source_update
where seq in
(
select  max(seq) ms  from source_update group by id
)
)  b
on (a.id=b.id)
when matched then
update set name=b.name

 

成功

 

当然对于

select * from source_update
where seq in
(
select  max(seq) ms  from source_update group by id
)

我们可以有更加有效的写法

select id,name
from
(
select seq, max(seq) over (partition by id ) s, id, name from source_update
)
where seq=s

 

但是不是所有特征的数据情况下,这些写法具有高效率。 说明

 

但是 由于不能确认id具有唯一性,又不能直接用update(merge)的方法, 游标集合提供了很好的方法

 

declare

          cursor c2 is select id,name from source_update orderby seq;

          type array is table of c2%rowtype index by binary_integer;

          l_array array;

          start_time int;

  begin                  

        start_time := dbms_utility.get_time;

          open c2;

          loop

                   fetch c2 bulk collect intol_array limit 10000;

                   exit when c2%notfound;

                                      

                   forall m IN  l_array.first..l_array.last

                   update target_update

set name=l_array(m).name

                   where id= l_array(m).id;

          end loop;

          close c2;

          dbms_output.put_line(( dbms_utility.get_time-start_time)/100);

          commit;  

  end;

讨论:你能根据已有的知识,做相关表的物理设计,使上述过程效率得到更大提高吗?

 

FORALL的部分更新

CREATE TABLEemp_temp (deptno NUMBER(2), job VARCHAR2(18));

 

 --INSERT INTO emp_temp VALUES (10, 'Clerk');

  --Lengthening this job title causes an exception

 --INSERT INTO emp_temp VALUES (20, 'Bookkeeper');

 --INSERT INTO emp_temp VALUES (30, 'Analyst');

 --COMMIT;

 

DECLARE

 TYPE NumList IS TABLE OF NUMBER;

 depts NumList := NumList(10, 20, 30);

BEGIN

 FORALL j IN depts.FIRST .. depts.LAST -- Run 3 UPDATE statements.

   UPDATE emp_temp SET job = job || ' (Senior)' WHERE deptno = depts(j);

  --raises a "value too large" exception

EXCEPTION

  WHEN OTHERS THEN

   DBMS_OUTPUT.PUT_LINE('Problem in the FORALL statement.');

    COMMIT; -- Commit results of successfulupdates.

END;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

FORALL影响的行数

(%BULK_ROWCOUNTAttribute)

游标具有以下属性

SQL%FOUND,

SQL%ISOPEN,

SQL%NOTFOUND,

SQL%ROWCOUNT,

这些属性记录了最近执行的DML语句的有关信息。

 

在FORALL中,引进了一个新的属性, %BULK_ROWCOUNT,这个属性实际上是一个数组,存放了第i次执行DNM操作的记录数。

 

CREATE TABLE emp_tempAS SELECT * FROM scott.emp;

 

select count(*) , deptno from emp_temp group by deptno

 

COUNT(*)

DEPTNO

6

30

5

20

3

10

 

DECLARE

TYPE NumList IS TABLE OF NUMBER;

depts NumList := NumList(10, 20, 30);

BEGIN

FORALL j INdepts.FIRST..depts.LAST

DELETE FROM emp_temp WHERE deptno = depts(j);

-- How many rows were affected by each DELETE statement?

FOR i IN depts.FIRST..depts.LAST

LOOP

DBMS_OUTPUT.PUT_LINE('Iteration #' || i || ' deleted '||SQL%BULK_ROWCOUNT(i) || ' rows.');

END LOOP;

END;

 

输出结果

Iteration #1 deleted 3 rows.
Iteration #2 deleted 5 rows.
Iteration #3 deleted 6 rows.

 

 

如果FORALL采用语法INDICES OF处理稀疏性集合%BULK_ROWCOUNT有同样的稀疏性;

如果FORALL采用语法VALUES OF处理一个子集合%BULK_ROWCOUNT则保持子集合相关的值。如果子集合包含重复的数据,则 has subscripts corresponding to the values ofthe elements in the index collection. If the index collection containsduplicate elements, so that some DML statements are issued multiple times usingthe same subscript, then the corresponding elements of %BULK_ROWCOUNT represent the sum of all rowsaffected by the DML statement using that

subscript.

 

DECLARE
TYPE
NumList IS TABLE OF NUMBER;
depts NumList := NumList(10, 20, 10,null,1001);
BEGIN
FORALL
j in INDICES OF depts
DELETE FROM emp_temp WHERE deptno = depts(j);
-- How many rows were affected by each DELETE statement?
FOR i IN depts.FIRST..depts.LAST
LOOP

DBMS_OUTPUT.PUT_LINE('Iteration #' || i ||' deleted ' ||SQL%BULK_ROWCOUNT(i)|| ' rows.');
END LOOP;
END;

-------------------------------------------------------------

Iteration #1 deleted 3 rows.
Iteration #2 deleted 5 rows.
Iteration #3 deleted 0 rows.
Iteration #4 deleted 0 rows.
Iteration #5 deleted 0 rows.

-----------------------------------------------------------------------------

 

DECLARE

TYPE NumList IS TABLE OF NUMBER;

depts NumList :=NumList(10, 20, 30,1001);

BEGIN

FORALL j in INDICES OF depts between 1 and 3

DELETE FROM emp_temp WHERE department_id = depts(j);

-- Howmany rows were affected by each DELETE statement?

FOR i IN 1..3

LOOP

DBMS_OUTPUT.PUT_LINE('Iteration #' || i || ' deleted' ||SQL%BULK_ROWCOUNT(i) || ' rows.');

END LOOP;

END;

 

--------------------------------------

Iteration #1 deleted0 rows.

Iteration #2 deleted0 rows.

Iteration #3 deleted5 rows.

 

通常对于insert %BULK_ROWCOUNT = 1, 因为一般情况下一次插入一条数据。但也可以一次插入多条数据。

 

CREATE TABLE emp_by_dept AS SELECTemployee_id, department_id

FROM hr.employeesWHERE 1 = 0;

 

DECLARE
  TYPE
dept_tab IS TABLEOF hr.departments.department_id%TYPE;
  deptnums dept_tab;
BEGIN
  SELECT
department_id BULKCOLLECT INTO deptnums FROM hr.departments;
  FORALL i IN1 .. deptnums.COUNT
    INSERT INTO
emp_by_dept
      SELECT employee_id,department_id
        FROM hr.employees
       WHERE department_id =deptnums(i);
  FOR i IN 1 ..deptnums.COUNT LOOP
    -- Counthow many rows were inserted for each department; that is,
    -- howmany employees are in each department.

    DBMS_OUTPUT.PUT_LINE('Dept' || deptnums(i) || ':inserted ' ||
                         SQL%BULK_ROWCOUNT(i)|| ' records');
  END LOOP;
  DBMS_OUTPUT.PUT_LINE('Totalrecords inserted: ' || SQL%ROWCOUNT);
END;

 

Dept 10: inserted 1 records
Dept 20: inserted 2 records
Dept 30: inserted 6 records
Dept 40: inserted 1 records
Dept 50: inserted 45 records
Dept 60: inserted 5 records
Dept 70: inserted 1 records
Dept 80: inserted 34 records
Dept 90: inserted 3 records
Dept 100: inserted 6 records
Dept 110: inserted 2 records
Dept 120: inserted 0 records
Dept 130: inserted 0 records
Dept 140: inserted 0 records
Dept 150: inserted 0 records
Dept 160: inserted 0 records
Dept 170: inserted 0 records
Dept 180: inserted 0 records
Dept 190: inserted 0 records
Dept 200: inserted 0 records
Dept 210: inserted 0 records
Dept 220: inserted 0 records
Dept 230: inserted 0 records
Dept 240: inserted 0 records
Dept 250: inserted 0 records
Dept 260: inserted 0 records
Dept 270: inserted 0 records
Total records inserted: 106

 

 

SQL%ROWCOUNT返回了最近FORALL的DML的影响的条数

 

%FOUND and %NOTFOUND refer only to the lastexecution of the SQL statement. You can use %BULK_ROWCOUNT to infer their values for individualexecutions. For example, when %BULK_ROWCOUNT(i) is zero, %FOUND and %NOTFOUND are FALSE and TRUE, respectively.

 

FORALL exception

 

处理FORALLExceptions (%BULK_EXCEPTIONS Attribute)

PL/SQL 提供了一种机制用来处理在FORALL DML过程中的例外信息。 这种机制开启了集合绑定操作中的例外信息,在遇到例外的时候,程序并没有退出而并作进一步处理。

 

 

%BULK_EXCEPTIONS 是一个数组记录了例外信息,它有两个字段组成:

1、%BULK_EXCEPTIONS(i).ERROR_INDEX

2、%BULK_EXCEPTIONS(i).ERROR_CODE

 

%BULK_EXCEPTIONS.COUNT.记录了例外的个数

 

You might need to work backward to determine whichcollection element was used in theiteration that caused an exception. For example, if you use the INDICES OF clause to process a sparse collection, you must stepthrough the elements one by one to find the onecorresponding to %BULK_EXCEPTIONS(i).ERROR_INDEX. If you use the VALUES OF clause to process a subset of elements, you must find theelement in the index collection whose subscript matches %BULK_EXCEPTIONS(i).ERROR_INDEX, and then use that element's value as thesubscript to find the erroneous element in the originalcollection.

 

If you omit the keywords SAVE EXCEPTIONS, execution of the FORALL statement stops when an exception is raised. In thatcase, SQL%BULK_EXCEPTIONS.COUNT returns1, and SQL%BULK_EXCEPTIONScontainsjust one record. If no exception is raisedduring execution, SQL%BULK_EXCEPTIONS.COUNT returns 0.

 

Drop tableemp_temp purge;
CREATE TABLE emp_temp AS SELECT * FROMhr.employees;

 

DECLARE
TYPE
empid_tab IS TABLE OFhr.employees.employee_id%TYPE;
emp_sr empid_tab;
-- create an exception handler for ORA-24381
errors NUMBER;
dml_errors EXCEPTION;
PRAGMA EXCEPTION_INIT(dml_errors, -24381);
BEGIN
SELECT
employee_id
BULK COLLECT INTO emp_sr FROM emp_temp
WHERE hire_date < to_date('30-12-94', 'dd-mm-yy');
-- add '_SR' to the job_id of the most senior employees
FORALL i IN emp_sr.FIRST..emp_sr.LAST  SAVE EXCEPTIONS
UPDATE
emp_temp SET job_id = job_id || '_SR'
WHERE emp_sr(i) = emp_temp.employee_id;
-- If any errors occurred during the FORALL SAVEEXCEPTIONS,
-- a single exception is raised when the statementcompletes.

EXCEPTION
-- Figure out what failed and why
WHEN dml_errors THEN
errors := SQL%BULK_EXCEPTIONS.COUNT;
DBMS_OUTPUT.PUT_LINE('Number of statements that failed: ' ||errors);

FOR i IN 1..errorsLOOP
DBMS_OUTPUT.PUT_LINE('Error #' || i ||' occurred during '||'iteration#' || SQL%BULK_EXCEPTIONS(i).ERROR_INDEX);
DBMS_OUTPUT.PUT_LINE('Error message is ' ||SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE));
END LOOP;
END;

 

Number of statements that failed: 51

Error #1occurred during iteration #1

Errormessage is ORA-12899: 列  的值太大 (实际值: , 最大值: )

Error #2occurred during iteration #2

Errormessage is ORA-12899: 列  的值太大 (实际值: , 最大值: )

Error #3occurred during iteration #9

Errormessage is ORA-12899: 列  的值太大 (实际值: , 最大值: )

.....................  

 

PL/SQL raises predefinedexceptions because updated values were

too large to insert into the job_id column. After the FORALL statement, SQL%BULK_

EXCEPTIONS.COUNT returned 2, and the contentsof SQL%BULK_EXCEPTIONSwere

(7,12899) and (13,12899).

To get the Oracle Database error message (which includesthe code), the value of

SQL%BULK_EXCEPTIONS(i).ERROR_CODE was negated and then passed tothe

error-reportingfunction SQLERRM, whichexpects a negative number.

 

我们要看那些数据引起了例外

增加

DBMS_OUTPUT.PUT_LINE('Error(' || i || ')  happens when employee_id='|| emp_sr(SQL%BULK_EXCEPTIONS(i).ERROR_INDEX));

 

Error (41) happens when employee_id=187

 

createtable EMP_TEMP

(

  EMPLOYEE_ID   NUMBER(6),

  FIRST_NAME    VARCHAR2(20),

  LAST_NAME     VARCHAR2(25) not null,

  EMAIL         VARCHAR2(25) not null,

  PHONE_NUMBER  VARCHAR2(20),

  HIRE_DATE     DATE not null,

  JOB_ID         VARCHAR2(10) notnull,

  SALARY        NUMBER(8,2),

  COMMISSION_PCT NUMBER(2,2),

  MANAGER_ID    NUMBER(6),

  DEPARTMENT_ID NUMBER(4)

)

 

selectlength(job_id), length( job_id || '_SR') from emp_temp whereemp_temp.employee_id=187

―――――――

8  11

 

return 与 集合

 

Drop tableemp_temp purge;
CREATE TABLE emp_temp AS SELECT * FROMhr.employees;

 

 

DECLARE
  TYPE NumList IS TABLE OFhr.employees.employee_id%TYPE;
  enums NumList;
  TYPE NameList IS TABLE OFhr.employees.last_name%TYPE;
  names NameList;
BEGIN
  DELETE FROM emp_temp
   WHERE department_id = 30

  RETURNING employee_id, last_name

  BULK COLLECT INTO
   enums, names;
  DBMS_OUTPUT.PUT_LINE('Deleted ' ||SQL%ROWCOUNT || ' rows:');
  FOR i IN enums.FIRST .. enums.LAST LOOP
    DBMS_OUTPUT.PUT_LINE('Employee #' ||enums(i) || ': ' || names(i));
  END LOOP;
END;

 

 

FORALL 与 return … bulk colect  

 

Droptable emp_temp purge;

CREATETABLE emp_temp AS SELECT * FROM hr.employees;

 

 

DECLARE
  TYPE
NumList IS TABLEOF NUMBER;
  depts NumList := NumList(10, 20, 30);
  TYPE enum_t IS TABLEOF hr.employees.employee_id%TYPE;
  TYPE dept_t IS TABLEOF hr.employees.department_id%TYPE;
  e_ids enum_t;
  d_ids dept_t;
BEGIN
  FORALL
j INdepts.FIRST .. depts.LAST
    DELETE FROM
emp_temp
     WHERE department_id =depts(j)

RETURNINGemployee_id, department_id

BULK COLLECTINTO e_ids, d_ids;
  DBMS_OUTPUT.PUT_LINE('Deleted' || SQL%ROWCOUNT || 'rows:');
  FOR i IN e_ids.FIRST.. e_ids.LAST LOOP
    DBMS_OUTPUT.PUT_LINE('Employee#' || e_ids(i) || ' from dept #' ||d_ids(i));
  END LOOP;
END;

 

那些例外的数据是否包含在return中

DECLARE

TYPE empid_tab IS TABLE OFhr.employees.employee_id%TYPE;

emp_sr empid_tab;

-- create an exception handler for ORA-24381

errors NUMBER;

dml_errors EXCEPTION;

PRAGMA EXCEPTION_INIT(dml_errors, -24381);

 

type typ_emp_id is table ofhr.employees.employee_id%type;

c_emp typ_emp_id;

 

BEGIN

SELECTemployee_id

BULK COLLECT INTO emp_sr FROM emp_temp

WHERE hire_date < to_date('30-12-94', 'dd-mm-yy')and rownum<=2;

-- add '_SR' to the job_id of the most senioremployees

FORALL i IN emp_sr.FIRST..emp_sr.LAST  SAVE EXCEPTIONS

UPDATE emp_temp SET job_id = job_id || '_S'

WHERE emp_sr(i) = emp_temp.employee_id

RETURNING employee_id bulk collect into c_emp;

 

dbms_output.put_line('______________________________');

 

for i in 1.. c_emp.count loop

dbms_output.put_line('ppp'||c_emp(i));

end loop;

 

EXCEPTION

 

WHENdml_errors THEN

errors := SQL%BULK_EXCEPTIONS.COUNT;

DBMS_OUTPUT.PUT_LINE('Number of statements thatfailed: ' || errors);

 

FOR i IN1..errors LOOP

DBMS_OUTPUT.PUT_LINE('Error (' || i || ')  happens when employee_id=' ||emp_sr(SQL%BULK_EXCEPTIONS(i).ERROR_INDEX));

END LOOP;

 

dbms_output.put_line('______________________________');

for i in 1.. c_emp.count loop

dbms_output.put_line('those records ofsuccess update is   '||c_emp(i));

end loop;

 

END;

 

注意红色部分代码的位置

 

Number of statements that failed: 1
Error (1)  happens when employee_id=206
______________________________
those records of success update is   198
those records of success update is   199
those records of success update is   200
those records of success update is   201
those records of success update is   202
those records of success update is   203
those records of success update is   204
those records of success update is   205
those records of success update is   100



原创文章,如果转载,请标注作者:田文  CSDN地址:http://blog.csdn.net/tiwen818

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值