PL/SQL详细介绍,设置oracle相关

Posted dy9776

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PL/SQL详细介绍,设置oracle相关相关的知识,希望对你有一定的参考价值。

1. 实现参照完整性
      指若两个表之间具有主从关系(即主外键关系),当删除主表数据时,必须确保相关的从表数据已经被删除.
  当修改主表的主键列数据时,必须确保相关从表数据已经被修改.为了实现级联删除,可在定义外部键约束时指定ON DELETE CASCADE关键字
  alter table emp add constraint fk_deptno foreign key (deptno) references dept(deptno) on delete cascade;

  实现级联更新,可以使用触发器
  create or replace trigger tr_update_cascade
  after update of deptno on dept
  for each row
  begin
    update emp set deptno=:new.deptno where deptno=:old.deptno;
  end;

2. 维护对象类型

     显示对象类型信息  执行CREATE TYPE 命令建立对象类型时,ORACLE会将对象类型的信息存放到数据字典中(USER_TYPES)
  select type_name,attributes,final from user_types;
  desc person_typ1

  增加和删除对象类型属性
 如果已经基于对象类型建立了对象类型或对象表,那么在对象类型增加或删除属性时必须要带有CASCADE关键字
  alter type preson_typ1 add attribute address varchar2(50) cascade
  alter type person_typ1 drop attrbute birthdate cascade;

  增加和删除对象类型方法
  alter type person_typ1 add member function get_info return varchar2 cascade;
  create or replace type body person_typ1 as
    member function get_info return varchar2 is
    begin
      return ‘雇员名:‘||name||‘,家庭住址:‘||address;
    end;
  end;

 

PL/SQL块中只能直接嵌入SELECT,DML(INSERT,UPDATE,DELETE)以及事务控制语句(COMMIT,ROLLBACK,SAVEPOINT),而不能直接嵌入DDL语句(CREATE,ALTER,DROP)和DCL语句(GRANT,REVOKE)

1.检索单行数据
  
  1.1使用标量变量接受数据
  v_ename emp.ename%type;
  v_sal   emp.sal%type;
  select ename,sal into v_ename,v_sal from emp where empno=&no;

  1.2使用记录变量接受数据
  type emp_record_type is record(
  ename emp.ename%type,sal emp.sal%type);
  emp_record emp_record_type;
  select ename,sal into emp_record from emp where empno=&no;

  1.3嵌入SELECT语句注意事项:
  使用SELECT INTO语句时,必须要返回一条数据,并且只能返回一条数据
  
  no_date_found:
  select into没有返回数据
  too_many_rows:
  select into返回多条数据
 
  where子句使用注意事项:
  使用的变量名不能与列名相同,否则触发TOO_MANY_ROWS例外.
 

2.操纵数据
  2.1使用VALUES子句插入数据
  v_deptno dept.deptno%type;
  v_dname dept.dname%type;
  v_deptno:=no;
  v_dname:=‘&name‘;
  insert into dept (deptno,dname) values(v_deptno,v_dname);

  2.2使用子查询插入数据
  v_deptno emp.deptno%type:=&no;
  insert into employee select * from emp where deptno=v_deptno;
 
  2.3更新数据
  使用表达式更新列值
  v_deptno dept.deptno%type:=no;
  v_loc dept.loc%type:=‘&loc‘;
  update dept set loc=v_loc where deptno=v_deptno;

  2.4使用子查询更新列值
  v_ename emp.ename%type:=‘&name‘;
  update emp set (sal,comm) = (select sal,comm from emp where ename=v_ename) where job = (select job from emp where ename=v_ename)

  2.5删除数据
  使用变量删除数据
  v_deptno dept.deptno%type:=&no;
  delete from dept where deptno=v_deptno;
  
  2.6使用子查询删除数据
  v_ename emp.ename%type:=‘&name‘;
  delete from emp where deptno=(select deptno from emp where ename=v_ename);

  
3.SQL游标
  游标是指向上下文区的指针,包括隐含游标(SQL游标)和显式游标两种类型
  SQL游标用于处理SELECT INTO ,INSERT,UPDATE以及DELETE语句.
  显式游标用于处理多行的SELECT语句
  SQL游标包括:SQL%FOUND,SQL%NOTFOUND,SQL%ROWCOUNT,SQL%ISOPEN等四种属性
  
  3.1 SQL%ISOPEN:执行时,会隐含的打开和关闭游标.因此该属性的值永远都是FALSE
  
  3.2 SQL%FOUND:用于确定SQL语句执行是否成功.当SQL有作用行时,为TRUE,否则为FALSE
  v_deptno emp.deptno%type:=&no;
  update emp set sal=sal*1.1 where deptno=v_deptno;
  if sql%found then dbms_output.put_line(‘执行成功‘);  else dbms_output.putline(‘失败‘); endif
  
  3.3 sql%notfound:确定SQL语句执行是否成功,当SQL有作用行时,为false,否则为true
  
  3.4 sql%rowcount:返回SQL语句所作用的总计行数
  v_deptno emp.deptno%type:=&no;
  update emp set sal=sal*1.1 where deptno=v_deptno;
  dbms_output.put_line(‘修改了‘||sql%rowcount||‘行‘);


4.事务控制语句
  事务控制语句包括COMMIT,ROLLBACK以及SAVEPOINT等三种语句
  
  v_sal emp.sal%type:=&salary;
  v_ename emp.ename%type:=‘&name‘;
  update emp set sal=v_sal where ename=v_ename;
  commit;
 exception
    when others then
      rollback;

  insert into temp values(1);
  savepoint a1;
  insert into temp values(2);
  savepoint a2;
  insert into temp values(3);
  savepoint a3;
  rollback to a2;
  commit;


5.控制结构
  条件分支语句
 
  5.1简单条件判断
  v_sal number(6,2);
  select sal into v_sal from emp where lower(ename)=lowe(‘&&name‘);
  if v_sal<2000 then update emp set sal=v_sal+200 where lower(ename)=lower(‘&name‘)
  end if

  5.2二重条件分支
  v_comm number(6,2);
  select comm into v_comm from emp where empno=&&no;
  if v_comm<>0 then update emp set comm=v_comm+100 where empno=&no;
  else update emp set comm=200 where empno=&no;
  end if

  5.3多重条件分支
  v_job varchar2(10);
  v_sal number(6,2);
  select job,sal into v_job,v_sal from emp where empno=&&no;
  if v_job=‘president‘ then update emp set sal=v_sal+1000 where empno=&no;
  elseif v_job=‘manager‘ then update emp set sal=v_sal+500 where empno=&no;
  else update emp set sal=v_sal+200 where empno=&no;
  end if;


  5.4 CASE语句:
  在CASE语句中使用单一选择符进行等值比较
  declare
   v_deptno emp deptno%type;
  begin
   v_deptno:=&no;
   case v_deptno
        when 10 then update emp set comm=100 where deptno=v_deptno;
        when 20 then update emp set comm=80  where deptno=v_deptno;
        when 30 then update emp set comm=50  where deptno=v_deptno;
   else
        dbms_output.put_line("不存在‘);
   end case;
   end;

   5.5 在CASE语句中使用多种条件比较
   declare
     v_sal emp.sal%type;
     v_ename emp.ename%type;
   begin
     select ename,sal into v_ename,v_sal from emp where empno=&no;
     case
       when v_sal<1000 then update emp set comm=100 where ename=v_ename;
       when v_sal<2000 then update emp set comm=80  where ename=v_ename;
       when v_sal<6000 tehn update emp set comm=50  where ename=v_ename;
     end case;
   end;


   5.6循环语句
   有基本循环,WHILE循环,FOR循环
   
   基本循环:一定要包含EXIT语句,定义循环控制变量
   create table temp(cola int);
   declare
     i int:=1;
   begin
     loop
       insert into temp values(i);
       exit when i=10;
        i:=i+1;
     end loop;
  end;

  5.7 WHILE循环:定义循环控制变量,并在循环体内改变循环控制变量的值
  declare
    i int:=1;
  begin 
    while i<=10 loop
      insert into temp values(i);
      i:=i+1;
    end loop;
  end;

  5.8 for循环:使用FOR循环时,ORACLE会隐含定义循环控制变量.
  for counter in[reverse]
  lower_bound..upper_bound loop
    statement1;
    statement2;
    .......
  end loop;
  5.9 counter是循环控制变量,并且该变量由ORACLE隐含定义,不需要显示定义;lower_bound和upper_bound分别对应循环控制变量的上下界值.默认情况下,FOR循环,每次会自动增一,指定REVERSE选项时,每次循环控制变量会减一
  begin
    for i in reverse 1..10 loop
      insert into temp values(i);
    end loop;
  end;

 
  5.10嵌套循环和标号:通过在嵌套循环中使用标号,可以区分内层循环和外层循环,并且可以在内层循环中直接退出外层循环
  declare
    result int;
    begin
    <<outer>>
    for i in 1..100 loop
    <<inter>>
    for j in 1..100 loop
    result:=i*j;
    exit outer when result=1000;
    exit when result=500;
    end loop inner;
    dbms_ouput.put_line(result);
    end loop outer;
    dbms_output.put_line(result);
    end;

    
6.顺序控制语句
  PL/SQL不仅提供了条件分支语句和循环控制语句,而且还提供了顺序控制语句GOTO和NULL.一般情况下不使用
   
  6.1 GOTO:用于跳转到特定标号处去执行语句.  
  GOTO LABEL_NAME;
  
  declare
    i int :=1;
  begin
    loop
      insert into temp values(i);
      if i=10 then
         goto end_loop
      end if;
      i:=i+1;
   end loop;
   <<end_loop>>
   dbms_output.put_line(‘循环结束‘);
   end;

  
   6.2 null:不会执行任何操作,并且会直接将控制传递到下一条语句.
   declare
     v_sal emp.sal%type;
     v_ename emp.ename%type;
   begin
     select ename,sal into v_ename,v_sal from emp where empno=&no;
     if v_sal<3000 then update emp set comm=sal*0.1 where ename=v_ename;
     else 
       null;
     end if;
   end;

   
7.复合数据类型
  7.1定义PL/SQL记录
  
  自定义PL/SQL记录:需要定义PL/SQL记录类型和记录变量,identifier用于指定记录变量名

  type type_name is record(
       field_declaration[,
       field_declaration]...
  );
  identifier type_name;
  
  declare
    type emp_record_type is record(
         name emp.ename%type,
         salary em.sal%type,
         dno emp.deptno%type);
    emp_record emp_record_type;


    使用%rowtype属性定义记录变量:可以基于表或视图定义记录变量
    当使用%ROWTYPE属性定义记录变量时,记录成员个数,名称,类型与表或视图列的个数,名称,类型完全相同.
    dept_record dept%rowtype;
    emp_record emp%rowtype;

   
    在select into 语句中使用PL/SQL 记录
    在select into 语句中使用记录变量
    set serveroutput on
    declare
      type emp_record_type is record(
           name emp.ename%type,
           salary em.sal%type,
           dno emp.deptno%type);
      emp_record emp_record_type;
    begin
      select ename,sal,deptno into emp_record from emp where empno=&no;
      dbms_output.put_line(emp_record.name);
    end;

    7.2在select into 语句中使用记录成员
    declare 
      type emp_record_type is record(
           name emp.ename%type,
           salary emp.sal%type,
           dna emp.deptno%type);
      emp_record emp_record_type;
    begin
      select ename,sal into emp_record.name,emp_record.salary from emp where empno=&no;
      dbms_output.put_line(emp_record.name);
    end;


    7.3在insert语句中使用PL/SQL记录
    在VALUES子句中使用记录变量
    declare 
      dept_record dept%rowtype;
    begin
      dept_record.deptno:=50;
      dept_record.dname:=‘administrator‘;
      dept_record.loc:=‘beijing‘;
      insert int dept values dept_record;
    end;

    在VALUES子句中使用记录成员
    declare
      dept_record dept%rowtype;
    begin
      dept_record.deptno:=60;
      dept_record.dname:=‘sales‘;
      insert into dept (deptno,dname) values (dept_record.deptno,dept_record.dname);
    end;

    7.4在UPDATE语句中使用PL/SQL记录
    在SET子句中使用记录变量
    declare
      dept_record dept%rowtype;
    begin
      dept_record.deptno:=30;
      dept_record.dnama:=‘sales‘;
      dept_record.loc:=‘shanghai‘;
      update dept set row=dept_record where deptno=30;
   end;

   在SET子句中使用记录成员
   declare 
     dept_record dept%rowtype;
   begin
     dept_record.loc:=‘guangzhou‘;
     update dept set loc=dept_record.loc where deptno=10;
   end;


  
   7.5在DELETE语句中使用PL/SQL记录:只能在DELETE语句中的WHERE子句中使用记录成员
   declare
     dept_record dept%rowtype;
   begin
     dept_record.deptno:=50;
     delete from dept where deptno=dept_record.deptno;
   end;


 
8.pl/sql集合
  处理单行单列数据,可以使用标量变量,处理单行多列的数据,可以使用PL/SQL记录
  处理单列多行数据,可以使用PL/SQL集合
  
  PL/SQL集合类型类似于高级语言数组的一种复合数据类型
  包括:索引表(PL/SQL表),嵌套表(NESTED TABLE),变长数组(VARRAY)三种
  
  8.1 索引表:PL/SQL表 元素个数没有限制,并且下标可以是负值
  定义索引表:
      type type_name is table of element_type [not null] index by key_type;
      identifier type_name;
  
  在索引表中使用BINARY_INTEGER和PLS_INTEGER
  set serveroutput on
  declare
    type ename_table_type is table of emp.ename%type index by binary_integer;
    ename_table ename_table_type;
  begin
    select ename into ename_table(-1) from emp where empno=&no;
    dbms_output.put_line(‘雇员名:‘||ename_table(-1));
  end;

  在索引表中使用VARCHAR2
  set serveroutput on
  declare 
    type area_table_type is table of number index by varchar2(10);
    area_table area_table_type;
  begin
    area_table(‘北京‘):=1;
    area_table(‘上海‘):=2;
    area_table(‘广州‘):=3;
    dbms_output.put_line(‘第一个元素:‘||area_table.first);
    dbms_output.put_line(‘最后一个元素:‘||area_table.last);
  end;

  8.2 嵌套表:元素个数从1开始,并且元素个数没有限制
  定义嵌套表:
      type type_name is table of element_type;
      identifier type_name;
   
      declare
        type ename_table_type is table of emp.ename%type;
        ename_table ename_table_type:=ename_table_type(‘A‘,‘A‘);


  在PL/SQL块中使用嵌套表:使用嵌套表变量时,必须首先使用构造方法初始化嵌套表变量,然后才能在块内引用嵌套表元素
  declare
    type ename_talbe_type is table of emp.ename%type;
    ename_talbe ename_table_type;
  begin
    ename_table:=ename_table_type(‘mary‘,‘mary‘,‘mary‘);
    select ename into ename_table(2) from emp where empno=&no;
    dbms_output.put_line(‘雇员名:‘||ename_table(2));
  end;


  在表列中使用嵌套表:
  在表列中使用嵌套表类型,必须首先使用CREATE TYPE命令建立嵌套表类型.
  当使用嵌套表类型作为表列的数据类型时,必须要为嵌套表列指定专门的存储表
  create type phone_type is table of varchar2(20);
  /
  create table employee(
     id number(4),name varchar2(10),sal number(6,2),
     phone phone_type
  )nested table phone store as phone_table;

  8.3 在PL/SQL块中为嵌套表列插入数据
  当定义嵌套表类型时,ORACLE自动为该类型生成相应的构造方法.当为嵌套表列插入数据时,需要使用嵌套表的构造方法
  begin
    insert into employee values(1,‘scott‘,800,phone_type(‘0471-3456788‘,‘13804711111‘));
  end;

  在PL/SQL块中检索嵌套表列的数据
  当在PL/SQL块中检索嵌套表列的数据时,需要定义嵌套表类型的变量接受其数据.
  set serveroutput on
  declare
    phone_table phone_type;
  begin
    select phone into phone_table from employee where id=1;
    for i in 1..phone_table.count loop
    dbms_output.put_line(‘电话:‘||phone_table(i));
    end loop;
  end;

 
  8.4 在pl/sql块中更新嵌套表列的数据
  更新嵌套表列的数据时,首先需要定义嵌套表变量,并使用构造方法初始化变量,然后才可在执行部分使用UPDATE语句更新数据
  declare
    phone_table phone_type:=phone_type(‘0471-3456788‘,‘13804711111‘,‘0471-2233066‘,‘13056278568‘);
  begin
    update employee set phone=phone_talbe where id=1;
  end;


  8.5变长数组(varray)
  VARRAY也是一种用于处理PL/SQL数组的数据类型, 它也可以做为表列的数据类型使用.
  元素下标以1开始,并且元素的最大个数是有限制的
  定义VARRAY的语法:
      type type_name is varray(size_limite) of element_type [not mull];
      identifier type_name;
  当使用VARRAY元素时,必须要使用其构造方法初始化VARRAY元素.

  declare 
    type ename_table_type is varrar(20) of emp.ename%type;
    ename_talbe ename_table_type:=ename_table_type(‘A‘,‘A‘);

  8.6 在PL/SQL块中使用VARRAY
  必须首先使用其构造方法来初始化VARRAY变量,然后才能在PL/SQL块内引用VARRAY元素
  declare
    type ename_table_type is varray(20) of emp.ename%type;
    ename_table ename_table_type:=ename_table_type(‘mary‘);
  begin
    select ename into ename_table(1) from emp where empno=&no;
    dbms_output.put_line(‘雇员名:‘||ename_table(1));
  end;

  在表列中使用varray
  要在表列中引用该数据类型,则必须使用CREATE TYPE命令建立VARRAY类型
  create type phone_type is varray(20) of varchar2(20);
  /
  create table employee(
    id number(4),name varchar2(10),
    sal number(6,2),phone phone_type);
  在PL/SQL块中操纵VARRAY列的方法与操纵嵌套表列的方法完全相同.嵌套表列元素个数没有限制,而VARRAY列的元素个数是有限制的.
 

  PL/SQL记录表
  PL/SQL变量处理单行单列数据
  PL/SQL记录处理单行多列数据
  PL/SQL集合处理多行单列数据
  PL/SQL记录表处理多行多列数据
  
  8.7 PL/SQL记录表结合了PL/SQL记录和PL/SQL集合的优点
  declare
    type emp_talbe_type is table of emp%rowtype index by binary_integer;
    emp_table emp_table_type;
  begin
    select * into emp_table(1) from emp where empno=&no;
    dbms_output.put_line(‘雇员姓名:‘||emp_table(1).ename);
    dbms_output.put_line(‘雇员姓名:‘||emp_table(1).sal);
  end;

  8.8 多级集合
  多级集合是指嵌套了集合类型的集合类型

  在PL/SQL块中使用多级VARRAY:实现多维数组功能
  定义二维VARRAY(10,10):
  declare
    type a1_varray_type is varray(10) of int;--定义一维VARRAY
    type na1_varray_type is varray(10) of a1_varray_type;--定义二维VARRAY集合
    --初始化二维集合变量
    nv1 nal_varray_type:=nal_varray_type(
        a1_varray_type(58,100,102),
        a1_varray_type(55,6,73),
        a1_varray_type(2,4);
    begin
      dbms_output.put_line(‘显示二维数组所有元素‘);
      for i in 1..nv1.count loop
          for j in 1..nv1(i).count loop
              dbms_output.put_line(‘nvl(‘||i||‘,‘||j||‘)=‘||nvl(i)(j));
          end loop;
      end loop;
   end;

  在PL/SQL块中使用多级嵌套表
  如果多维数组的元素个数没有限制,那么可以在嵌套表类型中嵌套另一个嵌套表类型
  
  8.9 二维嵌套表
  declare
    type a1_table_type is table of int;--定义一维嵌套表
    type nal_table_type is table of a1_table_type;--定义二维嵌套表集合
    --初始化二维集合变量
    nvl nal_table_type:=nal_table_type(
        a1_table_type(2,4),
        a1_table_type(5,73));
  begin
    dbms_output.put_line(‘显示二维数组所有元素‘);
    for i in 1..nvl.count loop
       for j in 1..nvl(i).count loop
           dbms_output.put_line(‘nvl(‘||i||‘,‘||j||‘)=‘||nvl(i)(j));
       end loop;
    end loop;
  end

  在PL/SQL块中使用多级索引表
  二维索引表:
  declare 
    type a1_table_type is table of int index by binary_integer;
    type nal_table_type is table of al_table_type index by binary_integer;
    nvl nal_table_type;
  begin
    nvl(1)(1):=10;
    nvl(1)(2):=5;
    nvl(2)(1):=100;
    nvl(2)(2):=50;
    dbms_output.put_line(‘显示二维数组所有元素‘);
    for i in 1..nvl.count loop
       for j in 1..nvl(i).count loop
          dbms_output.put_line(‘nvl(‘||i||‘,‘||j||‘)=‘||nvl(i)(j));
       end loop;
    end loop;
  end;

  
  8.10集合方法:ORACLE提供的用于操纵集合变量的内置函数或过程,其中EXISTS,COUNT,LIMIT,FIRST,NEXT,FRIOR和NEXT是函数
           而EXTEND,TRIM和DELETE则是过程
  集合方法只能在PL/SQL语句中使用,不能在SQL语句中使用.
  集合方法EXTEND和TRIM只适用于嵌套表和VARRAY,而不适合于索引表

  1.EXISTS:用于确定集合元素是否存在
  declare 
    type ename_table_type is table of emp.ename%type;
    ename_table ename_table_type;
  begin
    if ename_table.exists(1) then
       ename_table(1):=‘SCOTT‘;
    else
       dbms_output.put_line(‘必须初始化集合元素‘);
    end if;
  end;

  2.COUNT:用于返回当前集合变量中的元素总个数.
  declare
    type ename_table_type is table of emp.ename%type index by binary_integer;
    ename_table ename_table_type;
  begin
    ename_table(-5):=‘scott‘;
    ename_table(1):=‘smith‘;
    ename_table(5):=‘mary‘;
    ename_table(10):=‘blake‘;
    dbms_output.put_line(‘集合元素总个数:‘||ename_table.count);
  end;

  3.LIMIT:用于返回集合元素的最大个数.因为嵌套表和索引表的余数个数没有限制,返回NULL
        对于VARRAY来说,该方法返回VARRAY所允许的最大元素个数
  declare
    type ename_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.limit);
  end;

  4.FIRST和LAST:FIRST用于返回集合变量第一个元素的下标,而LAST方法则用于返回集合变量最后一个元素的下标
  declare
    type ename_table_type is table of emp.ename%type index by binary_integer;
    ename_table ename_table_type;
  begin
    ename_table(-5):=‘scott‘;
    ename_table(1):=‘smith‘;
    ename_table(5):=‘mary‘;
    ename_table(10):=‘blake‘;
    dbms_output.put_line(‘第一个元素:‘||ename_table.first);
    dbms_output.put_line(‘最后一个元素:‘||ename_table.last);
  end;

  5.FRIOR和NEXT:PRIOR返回当前集合元素的前一个元素的下标,而NEXT方法则用于返回当前集合元素的后一个元素的下标
  declare
    type ename_table_type is table of emp.ename%type index by binary_integer;
    ename_table ename_table_type;
  begin
    ename_table(-5):=‘scott‘;
    ename_table(1):=‘smith‘;
    ename_table(5):=‘mary‘;
    ename_table(10):=‘blake‘;
    dbms_output.put_line(‘元素5的前一个元素:‘||ename_table.prior(5));
    dbms_output.put_line(‘元素5的后一个元素:‘||ename_table.next(5));
  end;

  6.EXTEND:用于扩展集合变量的尺寸,并为它们增加元素.只适用于嵌套表和VARRAY.
         三种调用格式:EXTEND,EXTEND(N),EXTEND(N,I):添加N个元素,值与第I个元素相同
  declare
    type ename_table_type is varray(20) of varchar2(10);
    ename_table ename_table_type;
  begin
    ename_table:=ename_table_type(‘mary‘);
    ename_table.extend(5,1);
    dbms_output.put_line(‘元素个数:‘||ename_table.count);
  end;

  7.TRIM:用于从集合尾部删除元素,有TRIM和TRIM(N)两种调用格式.
       只适用于嵌套表和VARRAY
  declare
    type ename_table_type is table of varchar2(10);
    ename_table ename_table_type;
  begin
    ename_table:=ename_table_type(‘a‘,‘a‘,‘a‘,‘a‘,‘a‘);
    ename_table.trim(2);
    dbms_table.put_line(‘元素个数:‘||ename_table.count);
  end;

  8.DELETE:删除结合元素,但该方法只适用于嵌套表和索引表,不适用于VARRAY.
         有DELETE,DELETE(N),DELETE(M,N)三种调用方式.
         DETELE(M,N)删除集合变量从M到N之间的所有元素
  declare
    type ename_table_type is table of emp.ename%type index by binary_integer;
    ename_table ename_table_type;
  begin
    ename_table(-5):=‘scott‘;
    ename_table(1):=‘smith‘;
    ename_table(5):=‘mary‘;
    ename_table(10):=‘blake‘;
    ename_table.delete(5);
    dbms_output.put_line(‘元素总个数:‘||ename_table.count);
  end;

  
  8.11集合赋值
  使用嵌套表和VARRAY时,通过执行INSERT,UPDATE,FETCH,SELECT赋值语句,可以将一个集合的数据赋值给另一个集合.
  当给嵌套表赋值时,还可以使用SET,MULTISET UNION,MULTISET INTERSECT,MULTISET EXCEPT等集合操作符
  SET:用于取消嵌套表中的重复值.
  MULTISET UNION:取得两个嵌套表的并集(DISTINCT)
  MULTISET INTERSECT:用于取得两个嵌套表的交集.
  NULTISET EXCEPT:用于取得两个嵌套表的差集
  
  1.将一个集合的数据赋值个另一个集合
    源集合和目标集合的数据类型必须完全一致.
  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‘);
    dbms_output.put_line(‘name_array2的原数据:‘);
    for i in 1..name_array2.count loop
       dbms_output.put_line(‘ ‘||name_array2(i));
    end loop;
    dbms_output.new_line;
    name_array2:=name_array1;
    dbms_output.put(‘name_array2的新数据:‘);
    for i in 1..name_array2.count loop
       dbms_output.put(‘ ‘||name_array2(i));
    end loop;
    dbms_output.new_line;
  end;


  2.给集合赋NULL值:清空集合变量的所有数据(集合方法DETELE,TRIM也可以)
  declare
    type name_varray_type is varray(4) of varchar2(10);
    name_array name_varray_type;
    name_empty name_varray_type;
  begin
    name_array:=name_varray_type(‘scott‘,‘smith‘);
    dbms_output.put_line(‘name_array的原有元素个数:‘||name_array.count);
    name_array:=name_empty;
    if name_array is null then      
       dbms_output.put_line(‘name_array的现有元素个数:0‘);
    end if;
  end;

  3.使用集合操作符给嵌套表赋值
    
    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(i));
    end loop;
    dbms_output.new_line;
  end;

    2.使用MULTISET UNION操作符:取得两个嵌套表的并集.结果集中会包含重复值
  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(3,4,5);
    result nt_table_type;
  begin
    result:=nt1 MULTISET union nt2;
    dbms_output.put(‘result:‘);
    for i in 1..result.count loop
      dbms_output.put(‘ ‘||result(i));
    end loop;
    dbms_output.new_line;
  end;

  3.使用MULTISET UNION DISTINCT操作符:用于取得两个嵌套表的并集,并取消重复结果.
  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(3,4,5);
    result nt_table_type;
  begin
    result:=nt1 multiset union distinct nt2;
    dbms_output.put(‘result:‘);
    for i in 1..result.count loop
      dbms_output.put(‘ ‘||result(i));
    end loop;
    dbms_output.new_line;
  end;
  
  4.使用MULTISET INTERSECT操作符:用于取得两个嵌套表的交集
  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(3,4,5);
    result nt_table_type;
  begin
    result:=nt1 multiset intersect nt2;
    dbms_output.put(‘result:‘);
    for i in 1..result.count loop
      dbms_output.put(‘ ‘||result(i));
    end loop;
    dbms_output.new_line;
  end;
  
  5.使用MULTISET EXCEPT操作符:取得两个嵌套表的差集.在NT1中存在,但在NT2中不存在
  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(3,4,5);
    result nt_table_type;
  begin
    result:=nt1 multiset except nt2;
    dbms_output.put(‘result:‘);
    for i in 1..result.count loop
       dbms_output.put(‘ ‘||result(i));
    end loop;
    dbms_output.new_line;
  end;

  8.4比较集合
  函数cardinality用于返回嵌套表变量的元素个数   
  操作符SUBMULTISET OF用于确定一个嵌套表是否为另一个嵌套表的子集
  操作符MEMBER OF用于检测特定数据是否为嵌套表元素
  操作符IS A SET用于检测嵌套表是否包含重复的元素值
  操作符IS EMPTY用于检测嵌套表是否为NULL.
  
  1.检测集合是否为NULL
  declare
    type name_table_type is table of varchar2(10);
    name_table name_table_type;
  begin
    if name_table is empty then
       dbms_output.put_line(‘name_table未初始化‘);
    end if;
  end;

  2.比较嵌套表是否相同
  使用比较符=和!=检测两个嵌套表是否相同.不能比较VARRAY和索引表
  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_type(‘smith‘);
    if name_table1=name_table2 then
      dbms_output.put_line(‘两个嵌套表完全相同‘);
    else
      dbms_output.put_line(‘两个嵌套表数值不同‘);
    end if;
  end;

  3.在嵌套表上使用集合操作符
    在嵌套表上使用ANSI集合操作符CARDINALITY,MEMBER OF, IS A SET.不适用于VARRAY和索引表
    使用函数CARDINALITY
  declare
    type nt_table_type is table of number;
    nt1 nt_table_type:=nt_table_type(1,2,3,1);
  begin
    dbms_output.put_line(‘元素个数:‘||cardinality(nt1));
  end;

    使用操作符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,4);
  begin
    if nt1 submultiset of nt2 then
       dbms_output.put_line(‘nt1是nt2的子集);
    end if;
  end;

  使用操作符MEMBER OF :用于检测特定数据是否为嵌套表的元素.
  declare
    type nt_table_type is table of number;
    nt1 nt_table_type:=nt_table_type(1,2,3,5);
    v1 number:=&v1;
  begin
    if v1 MEMBER OF nt1 then
      dbms_output.put_line(‘v1是nt1的元素‘);
    end if;
  end;

  使用操作符IS A SET:用于检测嵌套表是否包含重复的元素值
  declare
    type nt_table_type is table of number;
    nt1 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;

 


  8.5批量绑定
  当在select,insert,update,delete语句上处理批量数据时,通过批量绑定,可以极大的加快数据处理速度,提高应用程序性能
  批量绑定是使用BULK COLLECT子句和FORALL语句来完成的
  BULK COLLECT 子句用于取得批量数据,该子句只能用于SELECT语句,FETCH语句和DML返回子句
  FORALL只适用于执行批量的DML操作

  1.不使用批量绑定
  declare
    type id_table_type is 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 is 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;


  8.6 FORALL语句
  执行批量insert,update,delete操作时,使用forall语句,FORALL不是循环语句
  oracle9i当使用FORALL语句时,必须具有连续的元素
  oracle10g通过使用indices of和values of子句,可以使用不连续的集合元素.
  forall三种执行语法:
  forall index in lower_bound..upper_bound sql_statement;
  forall index in indices of collection [between lower_bond.and.upper_bound] sql_statement;
  forall index in values of index_collection sql_statement;

  1.在insert语句上使用批量绑定
  declare
    type id_table_type is 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..10 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));
  end;

  2.在update语句上使用批量绑定
   declare
    type id_table_type is 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..5 loop
      id_table(i):=i;
      name_table(i):=‘n‘||to_char(i);
    end loop;
    forall i in 1..id_table.count 
       update demo set name=name_table(i) where id=id_table(i);
  end;

  3.在DELETE语句上使用批量绑定
  declare
    type id_table_type is table of number(6) index by binary_integer;
    id_table id_table_type;
  begin
    for i in 1..3 loop
      id_table(i):=i;
    end loop;
    forall i in 1..id_table.count 
      delete from demo where id=id_table(i);
  end;

  4.在FORALL语句中使用部分集合元素
  declare
    type id_table_type is table of number(6) index by binary_integer;
    id_table id_table_type;
  begin
    for i in 1..10 loop
      id_table(i):=11-i;
    end loop;
    forall i in 8..10
       insert into demo (id) values (id_table(i));
  end;

  5.在FORALL语句上使用INDECES OF子句:用于跳过NULL集合元素
  declare
    type id_table_type is table of number(6);
    id_table id_table_type;
  begin
    id_table:=id_table_type(1,null,3,null,5);
    forall i in indices of id_table
       delete from demo where id=id_table(i);
  end;
 
  6.在FORALL语句上使用VALUES OF子句
  create table new_demo as select * from demo where 1=0
  declare
    type id_table_type is table of demp.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 values(id_table(i),name_table(i));
  end;

  7.使用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;

 
  8.7 BULK COLLECT子句
  用于取得批量数据,只适用于select into 语句,fetch into 语句和DML返回子句
  可将批量数据存放到PL/SQL集合变量中
  1.在select 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
       dbms_output.put_line(‘雇员姓名:‘||emp_table(i).ename);
    end loop;
  end;

  2.在DML的返回语句中使用BULK COLLECT子句
  为了取得DML操作所改变的数据,可以使用RETURNING子句.
  declare
    type ename_table_type is table of emp.ename%type;
    ename_table ename_table_type;
  begin
    delete from emp where deptno=&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;
    dbms_output.new_line;
  end;


 

9.使用游标
  9.1当在PL/SQL块中执行查询语句SELECT和数据操纵语句DML时,ORACLE会为其分配上下文区(CONTEXT AREA),游标指上下文区指针
  对于数据操纵语句和单行SELECT INTO语句来说,ORACLE会为他们分配隐含游标.
  使用显示游标处理多行数据,也可使用SELECT..BULK COLLECT INTO 语句处理多行数据.

  1.显示游标
    定义游标
    cursor cursor_name is select_statement;
  2.打开游标:执行对应的SELECT语句并将SELECT语句的结果暂时存放到结果集中.
    open cursor_name;
  3.提取数据
    打开游标后,SELECT语句的结果被临时存放到游标结果集中,使用FETCH语句只能提取一行数据
    通过使用FETCH..BULK COLLECT INTO语句每次可以提取多行数据
    fetch cursor_name into variable1,varibale2,...;
    fetch cursor_name bulk collect into collect1,collect2,...[limit rows];
  4.关闭游标
    close cursor_name;
  
  9.2显示游标属性
    用于返回显示游标的执行信息,包括%isopen,%found,%notfound,%rowcount
  1.%isopen:确定游标是否打开 if cl%isopen then ... else  open c1; end if;
  2.%found:检查是否从结果集中提取到了数据 
    loop
      fetch c1 into var1,var2;
      if c2%found then ... else exit;
    end loop;
  3.%notfound
    loop 
       fetch c1 into var1,var2;
       exit when c2%notfound;
       ...
    end loop;
  4.%rowcount:返回当前行为止已经提取到的实际行数
    loop 
      fetch c1 into my_ename,my_deptno;
      if c1%rowcount>10 then
      ...
      end if;
      ...
    end loop;
  
  9.3显示游标使用示例
  1.在显示游标中使用fetch..into语句:只能处理一行数据,除非用循环语句
  declare
    cursor emp_cursor is select ename,sal from emp where deptno=10;
    v_ename emp.ename%type;
    v_sal emp.sal%type;
  begin
    open emp_cursor;
    loop
      fetch emp_cursor into v_ename,v_sal;
      exit when emp_cursor%notfound;
      dbms_output.put_line(v_ename||‘: ‘||v_sal);
   end loop;
   close emp_cursor;
  end;

  2.在显示游标中,使用FETCH..BALK COLLECT INTO语句提取所有数据
  declare
    cursor emp_cursor is select ename from emp where deptno=10;
    type ename_table_type is table of varchar2(10);
    ename_table ename_table_type;
  begin
    open emp_cursor;
    fetch emp_cursor bulk collect into ename_table;
    for i in 1..ename_table.count loop
        dbms_output.put_line(ename_table(i));
    end loop;
    close emp_cursor;
  end;

  3.在显示游标中使用FETCH..BULK COLLECT INTO ..LIMIT语句提取部分数据
  declare
    type name_array_type is varray(5) of varchar2(10);
    name_array name_array_type;
    cursor emp_cursor is select ename from emp;
    rows int:=5;
    v_count int:=0;
  begin
    open emp_cursor;
    loop
      fetch emp_cursor bulk collect into name_array limit rows;
      dbms_output.pur(‘雇员名‘);
      for i in 1..(emp_currsor%rowcount-v_count) loop 
        dbms_output.put(name_array(i)||‘ ‘);
      end loop;
      dbms_output.new_line;
     v_count:=emp_cursor%rowcount;
     exit when emp_cursor%notfound;
    end loop;
    close emp_cursor;
  end;

  4.使用游标属性
  declare
    cursor emp_cursor is select ename from emp where deptno=10;
    type ename_table_type is table of varchar2(10);    
    ename_table ename_table_type;
  begin
    if not emp_cursor%isopen then 
       open emp_cursor;
    end if;
    fetch emp_cursor bulk collect into ename_table;
    dbms_output.put_line(‘提取的总计行数:‘||emp_cursor%rowcount);
    close emp_cursor;
  end;

  5.基于游标定义记录变量
  declare
    cursor emp_cursor is select ename,sal from emp;
    emp_record emp_cursor%rowtype;
  begin
    open emp_cursor;
    loop
      fetch emp_cursor into emp_record;
      exit when emp_cursor%notfound;
      dbms_output.put_line(‘雇员名:‘||emp_record.ename||‘,雇员工资:‘||emp_record.sal);
    end loop;
  end;

 

 9.4参数游标
  定义参数游标时,游标参数只能指定数据类型,而不能指定长度.
  cursor cursor_name(parameter_name datatype) is select_statment;
  declare
    cursor emp_cursor(no number) is select ename from emp where deptno=no;
    v_ename emp.ename%type;
  begin
    open emp_cursor(10);
    loop
      fetch emp_cursor into v_ename;
      exit when emp_cursor%notfound;
      dbms_output.put_line(v_ename);
    end loop;
    close emp_cursor;
  end;

  9.5使用游标更新或删除数据
  要通过游标更新或删除数据,在定义游标时必须要带有FOR UPDATE子句
  cursor cursor_name(parameter_name datetype) is select_statement for update [of column_reference] [nowait];
  for update子句用于在游标结果集数据上家行共享锁,防止其他用户在相应行执行DML操作
  of子句确定哪些表要加锁,没有OF子句,则在所引用的全部表上加锁
  nowait子句用于指定不等待锁
  必须在UPDATE后DELETE语句中引用WHERE CURRENT OF子句
  update table_name set column=.. where current of cursor_name;
  delete table_name where current of cursor_name;
 

  1.使用游标更新数据
  declare
    cursor emp_cursor is select ename,sal from emp for update;
    v_ename emp.ename%type;
    v_sal emp.sal%tyep;
  begin
    open emp_cursor;
    loop
      fetch emp_cursor into v_ename,v_oldsal;
      exit when emp_cursor%notfound;
      if v_oldsal<2000 then
         update emp set sal=sal+100 where current of emp_cursor;
      end if;
    end loop;
    close emp_cursor;
  end;

  2.使用游标删除数据
  declare
    cursor emp_cursor is select ename,sal,deptno from emp for update;
    v_ename emp.ename%type;
    v_oldsal emp.sal%type;
    v_deptno emp.deptno%type;
  begin
    open emp_cursor;
    loop
      fetch emp_cursor into v_ename,v_oldsal,v_deptno;
      exit when emp_cursor%notfound;
      if v_deptno=30 then
         delete from emp where current of emp_cursor;
      end if;
    end loop;
    close emp_cursor;
  end;

  3.使用OF子句在特定表上加行共享锁
  declare
    cursor emp_cursor is select ename,sal,dname,emp.deptno from emp,dept where emp.deptno=dept.deptno
    for update of emp.deptno;
    emp_record emp_cursor%type;
  begin
    open emp_cursor;
    loop
      fetch emp_cursor into emp_record;
      exit when emp_cursor%notfound;
      if emp_record.deptno=30 then
         update emp set sal=sal+100 where current of emp_cursor;
      end if;
      dbms_output.put_line(‘雇员名:‘||emp_record.ename||‘,工资:‘||emp_record.sal||‘,部门名:‘||emp_record.dname);
    end loop;
    close emp_cursor;
  end;

  4.使用nowait子句
  通过在FOR UPDATE子句中指定NOWAIT语句,可以避免等待锁.若已经被作用行加锁,则提示错误信息
  declare
    cursor emp_cursor is select ename,sal from emp for update nowait;
    v_ename emp.ename%type;
    v_oldsal emp.sal%type;
  begin
    open emp_cursor;
    loop
      fetch emp_cursor into v_ename,v_sal;
      exit when emp_cursor%notfound;
      if v_oldsal<2000 then
        update emp set sal=sal+100 where current of emp_cursor;
      end if;
    end loop;
    close emp_cursor;
  end;

 

  9.6游标FOR循环
 

以上是关于PL/SQL详细介绍,设置oracle相关的主要内容,如果未能解决你的问题,请参考以下文章

ORACLE PL/SQL:以最大执行时间调用外部 Oracle PL/SQL 过程

oracle PL/SQL 包的介绍

如何用PL/SQL Developer连接Oracle数据库

如何用PL/SQL Developer连接ORACL数据库

如何配置pl/sql 连接远程oracle服务器

Oracle PL/SQL 第五章–复合类型