1.索引、事务、触发器、存储过程、游标、程序包

pl/sql基本语法

-----------------------自定义异常--------------------------------------------------------------------

定义部分: 声明异常变量   exception_name   exception;

执行部分:抛出异常  raise  exception_name;

异常处理部分: 捕获异常

 

------------------------创建过程----------------------------------------------------------------------

  create or replace procedure procedure_name(参数)
  is / as
    local variable declaration
  begin
    executable   statements
  exception 
    exception handlers
  end;

     

执行存储过程: in 模式调用存储过程exec   procedure_name()

                          out 模式调用存储过程时,需要在其他pl/sql中进行调用

                          inout模式调用存储过程时,需要在其他pl/sql中进行调用

过程参数三种模式

in:用于接受调用程序的值

      默认的参数模式

out :用于向调用程序返回值

in out:用于接受程序的值,并向调用程序返回更新的值

 例 1:编一个 输入两个数字并使得两个数字交换输出的存储过程

定义    

 create or replace procedure  procedure1(p1 in out number, p2 in out number)
  as
  v_temp number;
  begin
    v_temp :=p1;
    p1 := p2;
    p2 :=v_temp;
  end;

调用:

  

declare 
    num1  number :=100;
    num2  number :=200;
  begin 
    proceduref1(num1,num2);
    dbms_output.put_line( 'num1 =' || num1,'num2 =' ||num2);
  end;

   

--------------------------------函数---------------------------------------------------------------------------------

函数是可以返回值的命名的pl/sql子程序

定义函数的一些限制 :函数只能接受in参数,而不能接受out  或者 in out模式参数

          形参不能是pl/sql类型,只能是数据库类型

          函数的返回类型也必须是数据库类型

创建函数的语法:

create or replace function function_name(参数)
  return 数据类型
  as
    变量
  begin
    executable statements;
    return result;
  exception
    exception handlers;
  end;

例1: 

 create or replace function function1 return varchar2
   as
     begin
    return   ‘你好,朋友’;
     end;

  sql.plus 中调用函数方法:  

select  function1  from  dual;

  在pl/sql代码块中运行方法:

declare
  ss  varchar2(20);
   begin
  ss:=function1;
       dbms_output.put_line(ss);
    end;

例2:创建一个函数,可以接受用户输入的学号,得到该学生的名次,并输出这个名次

学生成绩表(sno,name,score)

  

create or replace function function2(sno1 int) return int
  as
  score1  number;
  mingci1 number;
  begin 
    select   score into  score1 from  student  where  sno = sno1;
    select   count(*)  into  mingci1  from student  where  score >score1;
    return  mingci+1;
  end;

-------------------------        索引       ---------------------------------------------------------------------------

索引分类:B树索引、位索引

1.创建标准索引

   create index index_name 
   on  table_name(column1…);

2,创建唯一索引

create unique index  index_name 
on table_name(column1…);

3,.创建位索引 

create bitmap index index_name
on  table_name(column1…);

------------------------------------     事务       -----------------------------------------------------------

原子性、一致性、隔离性、永久性

设置自动提交:set autocommit on/off

-----------------------------------      游标     --------------------------------------------------------------------

游标分类:隐式游标:在pl/sql程序中执行dml sql语句时自动创建隐式游标,名称固定:sql

     显示游标 :显示游标用于处理返回多行的查询

     ref游标 :ref游标用于处理运行时才能确定的动态sql查询的结果

游标的四种属性:

  %found         sql语句影响了一行或者多行时为true

  %notfound    sql语句没有影响任何行时为true

  %rowcount    sql语句影响的行数

  %isopen        游标是否打开

声明游标、打开游标、提取游标数据、关闭游标 

两个常见异常 :

  没有查找出数据:no_date_found

    返回过多行数:too_many_rows

 

例1 使用游标取出学生记录表中的所有记录 student(sno,sname,sage) 

declare
    stu1  student%rowtype;
    cursor  mycursor  is select  * from student;
  begin
    open  mycursor;
    fetch mycursor  into stu1  ;
    while  mycursor%found loop
      dbms_output.put_line('学号是:'  || stu1.sno || '学生名为:' || stu1.sname ||'学生年龄为;' || stu1.sage);    
              end  loop;
    close mycursor;
  end

对显示游标添加参数

  

declare
    sno1 student.sno%type;
    stu1  student%rowtype;
    cursor  mycursor( input_no  number)  is select  * from student where  sno >input_no;
  begin
    sno1 :=&学生学号;
     open  mycursor(sno1);
    fetch mycursor  into stu1  ;
    while  mycursor%found loop
      dbms_output.put_line('学号是:'  || stu1.sno || '学生名为:' || stu1.sname ||'学生年龄为;' || stu1.sage);    
              end  loop;
    close mycursor;
  end

允许使用游标删除或更新活动集中的行   声明游标时必须使用  select …for  update语句

 声明时 

 cursor cursor_name is select  statement  for update;

 在更新语句时  

update table_name   
set set_clause
where  current of cursor_name   --当缺少该行时,会对表中的所有数据行进行更新两次

例3:使用游标  对2号或者3号的学生进行记录修改

 declare
    stu1  student%rowtype;
    cursor  mycursor  is select  * from student where sno=2 or sno =3 for update;
  begin
    open  mycursor;
    fetch mycursor  into stu1  ;
    while  mycursor%found loop
      update student
      set sno = sno +10;
      where current of mycursor;
      fetch  mycursor into stu1;   
              end  loop;
    close mycursor;
  end

显示游标例

  两张表  student(xh number , xm varchar2(10))  address (xh number, zz varchar2(10)完成 给表student添加一列zz 是varchar2(10)类型,再从address中,将zz字段的数值取出来,对应的插入到表student新增的zz列中 

alter table studnet add zz varchar2(10);
  declare
    xh1 number;
    zz1 varchar2(10);
    cursor  cursor1 is select xh,zz  from address;
  begin
    open cursor1;
    fetch cursor1 into xh1,zz1 ;
    while  cursor1%found loop
      update student  set zz=zz1 where xh = xh1;
    end loop;
    close cursor1;
  end;

循环游标:只能进行select 不能进行update

写法: 

for  <record_index> in <cursor_name> loop 
   <executable statements>
end loop;
declare
  stu1  student%rowtype;
  cursor  mycursor  is select  * from student;
begin
  for cur_2 in  mycursor loop
  dbms_output.put_line('学号是:'  || cur_2.sno || '学生名为:' || cur_2.sname ||'学生年龄为;' ||cur_2.sage);
  end loop;

end

在大量数据处理情况下:

fetch cursor_name bulk collect into variable;
--
fetch cursor_name into variable --效率高、速度快

ref游标

创建ref游标变量两个步骤:

  声明ref游标类型

  声明ref游标类型的变量

--用于声明ref游标类型的语法:
type  <ref_cursor_name> is ref cursor
[return  <return_type>];
--打开游标 变量的语法
open cursor_name for select_statement;

例子:使用ref游标查询student(sno,sname)表中的姓名

  declare 
    type  refcur  is ref cursor;
    cursor2 refcur;

    tab varchar2(50);
    tab_name  varchar2(50);
    sno1  student.sno%type;
    sname1 student.sname%type;
  begin
    tab_name := '&tab';
    if  tab_name ='studnet'  then
      open cursor2 for select sno,sname form student;
      fetch cursor2 into sno1,sname1;
      while corsor2%found loop
        dbms_output.put_line('学号为:' || sno1 || '姓名为:' || sname1);
      end loop;
      close cursor2;
    else  
      dbms_output.put_line('输入为不正确的表名');           
    end if;
  end;

显示游标和ref游标一起使用

例:学生表student(xh number ,kc varchar2(10));  生成student2表(xh number ,kc varchar(50)) 要求对应于每个学生,求出他的总的 选课记录,把 每个学生的选课记录插入到student2表中,即将一位学生的所有记录 放入student2表中的kc中 

 1 declare 
 2     xh1  student.xh%type;
 3     kc1   varchar2(50) := ''; --保存对应学生的课程
 4     kc2   varchar2(50);
 5     
 6     cursor cursor1 is select  distinct(xh) from student;
 7     type  refcur  is  ref  cursor;
 8     cursor2  refcursor;
 9 
10 begin 
11     open  cursor1 ;
12     fetch cursor1 into xh1;
13     while cursor1%found loop
14             kc1 := '';
15             open cursor2 for select kc from student where xh = xh1;
16             fetch cursor2 into kc2;
17             while cursor2%found loop
18                     kc1 := kc1 || kc2;
19                     fetch cursor2 into kc2;
20              end loop;
21             close cursor2;
22             insert  into student2 values(xh1,kc1);
23             commit;
24             fetch cursor1 into xh1;
25     end loop;   
26     close cursor1;
27 end;                

-----------------------------      触发器     ------------------------------------------------------------

create [or replace] trigger  trigger_name
after / before / instead of           -- after触发器的工作原理:先保存数据库数据的更新,再激活触发器
                                      --before触发器的工作原理:先激活触发器,再保存更新数据库数据
[ insert]  [ [or] update [of column_list] ]  [ [or] delete]
on table_or_view_name
[referencing {old [as] old / new [as] new} ]
[for each row]  --行级触发器,如果没有该行就是表级触发器
[when  condition]
pl/sql_block;

   --new   代表用户即将插入数据库中的某行记录的新表值
   --old   代表即将删除的该行数据记录得旧表值

触发器中不能使用 :rollback、commit、create、 dorp、 alter、 savepoint等内容

触发条件谓词:当插入数据时触发谓词inserting

                         当进行更新数据时的触发谓词updating

       当进行删除数据时的触发谓词deleting

例1:当用户插入或更新 成绩表中的记录时候,就输出一个提示“触发器响应了”

create  or replace trigger  trigger1
before insert or update on 成绩表
begin
        dbms_output.put_line('触发器响应了');
end

例2:当向学生表中插入数据时,需要控制学生学号不可以为负数 

create  or replace trigger trigger2
        before  insert on student  
  for each row
  begin 
    if  now.sno <0   then 
      raise_application_error(-2001,'学号错误,不能插入表中');
    end ifend

 例3:当向学生表 中插入 数据时,需要控制学生学号 不能为负数,如果为负数,则将负数改为绝对值的正数插入 

create or replace trigger trigger3 
before insert on student 
for each row
begin 
  if  :now.no<0  then 
    now.sno  :=   -now.sno;
  end if;
end;

常用的系统变量 

ora_client_ip_address     --返回客户端的ip地址
ora_database_name         --返回当前 数据库名
ora_login_user            --返回登录用户名
ora_dict_obj_name         --返回ddl 操作所对应的数据库对象名
ora_dict-obj_type         --返回ddl操作所对应的数据库对象类型

instead  of触发器:修改视图中,非键值表中的列 定义在视图上,用来替换实际的操作语言

例4:学生表(sno,sname,sage)

         住址表(sno,zname)

        视图(sno,sname,zname)更新视图 将学生名为kite的住址换成安徽

  create or replace trigger trigger4
  instead of  update  on view_stu_add  
  for each row
  declare 
         aa  number :=0;
   begin
       select  sno  into  aa  from student   where sname = old.sname;
        delete from  address    where   sno   =  aa;
          insert  into  address  values(aa,:new.zz);
   end;
   update view_stu_add  set  zname ='安徽' where sname = 'kite';

例5:当用户对学生成绩表student(sno,sname,score)进行增删改的时候,将当时情况输出 出来,增加时,记录增加的信息,更新时,记录更新前、后的记录信息,删除的时候 ,记录删除的记录 

create or replace trigger trigger5
  before  insert or update or  delete  on student
  for each row
  begin  
    if  inserting then 
      dbms_output.put_line('插入的学生 学号是:'|| new.sno || '姓名是:' || new.sname ||'成绩是 :'|| new.score);
    end if;
    if  updating   then
      dbms_output.put_line('原始学生的学生 学号是:'|| old.sno || ‘姓名是:’ || old.sname ||'成绩是 :'|| old.score);
      dbms_output.put_line('新的学生的学生 学号是:'|| new.sno || '姓名是:' || new.sname ||'成绩是 :'|| new.score);
    end if;
    if  deleting then 
      dbms_output.put_line('删除的学生 学号是:'|| old.sno || ‘姓名是:’ || old.sname ||'成绩是 :'|| old.score);
    end if;
  end; 

--------------------------------     程序包    ---------------------------------------------------------------

程序包 :是对于相关过程、函数、变量、游标和异常等对象的封装

程序包的组成部分:包规范(包头)、包主体(包体)组成

包头:公用类型的变量、常量、异常 、过程、函数等的 声明

包体:私有类型的变量、常量、异常 、过程、函数等的 声明,以及包头内的过程、函数的实现。

创建包头的语句: 

create or replace package package_name  
  is/as
  public item declarations   --公有对象:在包的外部也可使用
  subprogram specification
  end  package_name;

创建包体的语句: 

create or replace package body package_name
is/as
private item declarations --私有对象:只能在包体之内使用,范围超出包体则不可再使用
subprogram bodies
begin
  initialization
end package_name;

程序包中的存储过程:

例1: 两张表  student(sno,snme,sage)、address(sno,zz)

create or replace package pack1
is 
  aa int :=9; --公共变量,包外依然可访问应用
  procedure  insert_student(a1 in student%rowtype); --声明存储过程
  procedure uppdate_student(a2 in student%rowtype);--声明存储过程
end pack1;
create or replace package body pack1 is   bb int :=5; --私有变量 使用范围 包的内部   procedure insert_student(a1 in student%rowtype)   is   begin     insert into student(sno,sname,sage)     values(a1.sno,a1.sname,a1.sage);     commit;     dbms_output.put_line(pack1.bb);   end insert_student;   procedure update_student(a2 in student%rowtype) --根据传入参数的学号,修改学生名   is   begin     update student set sname = a2.sname where sno = a2.sno;     commit;   end update_student;
end pack1;   execute dbms_output.put_line(pack1.aa); --可输出结果   execute dbms_output.put_line(pack1.bb);--不可输出结果

包的使用:在pl/sql程序块中

declare 
    a1 student%rowtype;
  begin 
    a1.sno :=8;
    a1.sname:='AA';
    a1.sage "=24;
    pack1.insert_studnet(a1);
  end;


  declare 
    a2 student%rowtype;
  begin 
    a2.sno :=8;
    a2.sname :='BB';
    a2.sage = 27;
    pack1.update_studnet(a2);
  end;

程序包中的游标

       游标的定义分为游标规范和游标主体两部分

  在包规范中声明游标规范时必须使用return子句指定游标的返回类型

return 子句指定的数据类型可以是:

  用%rowtype 属性引用表定义的记录类型;

  定义的记录类型,例如:type emprectyp is record( emp _id integer, salary real)来定义的

  不可以是number、varchar2、%type等类型

程序包内,使用显示游标

create or replace package pack2 is
    cursor mycursor return student%rowtype;
    procedure mycursor_use;
end pack2;
create or replace package body pack2 is 
  cursor mycursor  return studnet%rowtype  is select * from student;
  procedure mycursor_use
   is 
    stu_rec studnet%rowtype;
  begin
    open mycursor;
    fetch mycursor into stu_rec;
    while mycursor%found loop
      dbms_output.put_line( '学号是' || stu_rec.sno || ‘姓名是’ || stu_rec.sname || '年龄是' || stu_rec.sage);
      fetch mycursor into stu_rec;
    end loop;
    close mycursor;
  end mycursor_use;
end pack2;

  exec pack2.mycursor_use; 

程序包内,使用 ref 游标

create or replace package pack3 is 
    type refcur is ref cursor;
     procedure mycursor_use;
end pack3;

create or replace package body pack3 is 
    procedure mycursor_use
    is 
        mycursor refcur;
        stu_rec student%rowtype;
    begin
        open mycursor for select * from student;
        fetch  mycursor into stu_rec;
        while mycursor%found loop
                 dbms_output.out_line('学号是:' || stu_rec.sno || '姓名是:'||stu_cur.sname);
                 fetch mycursor into stu_rec;
        end loop;
        close mycursor;
    end mycursor_use;
end pack3;

--执行
execute pack3.mycursor_use;
原文地址:https://www.cnblogs.com/sun1997/p/13398626.html