zoukankan      html  css  js  c++  java
  • oracle数据库笔记1PL/SQL基础5子程序

    在PL/SQL程序块中,可以定义子程序(过程和函数),以使代码更加模块化。
    
    
    子程序是命名的PL/SQL块,它可带参数,可被调用。一般过程
    子程序执行一个动作, 函数用于计算一个值。
    
    1.定义局部过程的语法形式:
    
    DECLARE                   -- PL/SQL块的说明关键字
     
            PROCEDURE  过程名[(参数表)]  IS      --过程说明
    
                     说明部分
             BEGIN   
    
                     执行部分                    /*  过程体  */
     
             EXCEPTION
                     
                     例外处理部分
          
             END;
    
    
    
    其中参数说明形式:
    
    参数名[ IN, OUT, INOUT] 类型
     [:=  |  DEFAULT  值]
    
    
    IN 参数可将值传送给被调用的子程序;
    OUT参数将值返回给子程序的调用者
    INOUT参数可将初始值传送给被调用的子程序,并将修改的    
    值返回调用者。即既可向过程传递值,也可从过程中返回值
    
    在过程内,一个IN参数起象常量一样的作用,它不能被赋值
    
    当过程被调用时,必须为该参数指定值
    
    一个OUT参数起像一个未被初始化的变量的作用,它的值不可赋给其它变量或重新赋给自己
    在退出过程前,要显示地将值赋给全部OUT形式参数
    
    一个IN OUT 参数,它起象初始化的变量的作用,可被赋值,它的值可以赋给其它变量
    
    对IN参数可初始化为缺省值
    
    在支持PL/SQL的任何工具中可定义过程。如果要使它通用,过程必须用CREATE命令建立, 并存储在ORACLE数据库中
    
    使用参数应注意以下原则:
    
    1).  参数类型可以是ORACLE允许的任一类型,还可以用
      %TYPE 或 %ROWTYPE 来指定参数类型。
    2).   指定参数类型时不能加长度限制。
    3).  所有输出参数(OUT)在过程体中只能出现在SELECT语句的 INTO子句中, 或出现在赋值号左边
    4).   应尽量减少IN参数个数
    
    PROCEDURE  raise_sal (emp_id  integer, increase  real) IS
    
            cur_salary    real ;
     
           salary_mis  EXCEPTION ;
    BEGIN
    
             select  sal  into  cur_salary
    
             from  emp
    
             where  empno=emp_id;
    
             IF  cur_salary  IS  NULL  THEN
    
                 RAISE  salary_mis;
    
             ELSE
    
                update   emp
    
                set  sal=sal+increase
    
                where  empno=emp_id;
    
             END  IF;
    
    
    EXCEPTION
    
            WHEN  NO_DATA_FOUND   THEN
     
                  insert  into    emp_audit
    
                  values( emp_id, ‘NO  such  number’);
    
            WHEN  salary_mis  THEN
    
                   insert  into  emp_audit
    
                  values (emp_id,’SALARY  IS  NULL’);
    
    END;( end raise_sal ;)
    
    
     用一个PL/SQL语句调用其过程,调用语句形式为:
    
                     raise_sal(1001, 500);   
          
    或用:     raise_sal(increase=>500, emp_id=>1001);
    
    
    带有in和in out参数的过程:
    
    Create  or replace procedure multi_params(mymesg1 in varchar2,mymesg2 out varchar2,mymesg3 in out varchar2) is
    
    Begin
    	
      mymesg2:=mymesg1||’ parameter as the out’;
    	
      mymesg3:=mymesg3||’ returned’;
    
    End multi_params;
    
    
    调用过程multi_params
    
    
    Declare 
      
    Inparm varchar2(50):=‘this is the in’;
      
    Outparm varchar2(50);
      
    Inoutparm varchar2(50):=‘and this is the in out’;
    
    begin
      multi_params(inparm,outparm,inoutparm);
    
    	dbms_output.put_line(outparm||’ ‘||inoutparm);
    
    End;
    
    
    带游标的存储过程:
    
    1.显示定义游标的方法
    
    Create or replace procedure emp_cur_proc is
    
    	Cursor emp_cur is select ename from emp;
    
    Begin
    
     	for emp_rec in emp_cur loop
    
    	   Dbms_output.put_line(emp_rec.ename);
            End loop;
    
    End emp_cur_proc;
    
    
    2.隐式定义游标
    
    Create or replace procedure imp_curpro 
    Is
     
    begin
    
    	For emp_rec in (select ename from emp) loop
    
    		Null;  --可以执行任何需要的语句
    
    	End loop;
    
    End imp_curpro;
    
    3带批量绑定的存储过程
    
    Create or replace procedure bulk_bind_proc
     Is
    
       Type bbp is table of emp.ename%type index by binary_integer;
       
    Temp_bulk bbp;
    
    Begin
       
    Select ename bulk collect into tmp_bulk from emp;
    
    End bulk_bind_proc;
    
    有关Oracle存储过程的相关问题:
    
    1.在oracle中,数据表别名是不能加as的,例如:
    select a.appname from appinfo a;—— 正确
      
    select a.appname from appinfo as a;—— 错误
    
    
    2.在存储过程中,select某一字段时,后面必须紧跟into,假如select整个记录,利用游标的话就另当别论了。
    
    3.在我们利用select……into……语法时,必须先确保数据库中有该条记录,否则会报出"no data found"异常。
    
    可以在该语法之前,先利用select count(*) from 查看数据库中是否存在该记录,如果存在,再利用select……into……
    
    
    4.请注意,在存储过程中,别名不能和字段名称相同,否则虽然编译可以通过,但在运行的阶段会报错
    
    5.在存储过程中,关于出现null的问题
    假如有一个表X,定义如下
    create table X(
    id varchar2(50) primary key not null;
    vcount number(8) not null;
    bid varchar2(50) not null
    );
    
    假如在存储过程中,使用如下语句:
    select sum(vcount) into fcount from X where bid='xxxxxx';
    如果X表中不存在bid="xxxxxx"的记录,则fcount=null
    即使fcount定义时设置了默认值,例如:fcount number(8):=0依然无效,fcount还是会变成null
    这样以后使用fcount时就可能会出现问题
    
    所以在这里我们最好先判断一下:
    if fcount is null then fcount:=0; 
    end if; 
    
    函数子程序
    
    FUNCTION   sal_ok(salary  real, title char) 
      RETURN  boolean  is           /* 函数返回值是逻辑值  */
     
      max_sal  real;
    
      min_sal  real;
           
    BEGIN  
       
      select  max(sal), min(sal)   INTO  max_sal, min_sal
    
      from  sals
    
      where  job=title;
      RETURN (salary>=min_sal) AND
      (salary<=max_sal);
    END;
    
    函数调用是以表达式的形式,通过调用返回一个计算值
    
    if   sal_ok(new_sal,  new_ title)  then  
     …  
    end if ;  
    
    也可以将函数调用返回值赋值给一个布尔变量
    
    调用用户定义的函数可在过程性语句中使用,可以在表达式中 
    调用该函数,但不能在SQL语句中使用
    
    函数的调用必须作为表
    达式的一部分
    
    函数中使用RETURN语句,该语句的作用是立即完成子程序的
    执行,并将控制返回给调用者
    
     RETURN        PL\SQL  表达式 ;
    
    
    一个子程序可包含多个RETURN语句
    
    对于过程, RETURN语
    
    句不能包含表达式,
    
    对于函数, RETURN必须包含一个表达式
    
    在PL\SQL块中创建函数子程序。
    declare
     
              function  sepl(dept_no  in  number)
     
              return  varchar2   is
     
              tmp  varchar2(30);
     
              begin
    
                     if  dept_no>=100  or  dept_no<1  then
                         return  null ;
    
                     else
    
                         select  to_char( to_date( lpad(to_char(dept_no), 4,‘0’),‘YYYY’), ‘YEAR’) into tmp
     
                       from  dual;
                       return  tmp;
                     end  if ;
     
               end;
    begin
    
              dbms_output.put_line(sepl(22));   /*  输出为: TWENTY_TWO */
     
              dbms_output.put_line(sepl(15));     /*  输出为:  FIFTEEN  */
               
    end;  
    
     在一个PL\SQL块中,说明多个子程序。
    declare
            
              function  hello
              return  varchar2  is
     
             begin
    
                return ‘world’;
    
              end;
    
             procedure  call_hello  is
    
               begin
     
                dbms_output.put_line(hello);
    
               end;
    begin
    
             call_hello ;
    end ;    
    
    在PL/SQL程序中, 定义的过程,函数子程序,主模块可以调用子程序模块
    
    后定义的子程序可以调用先定义的子程序,即在PL/SQL程序中,使用一个标识符之前必须先说明
    
    若先定义的子程序调用后定义的子程序可进行向前说明   
    
    向前说明是:
     
      被向前调用的子程序的说明部分放在调用它的子程序说明之前, 用“;”表示结束。
    
    
    
    
    存储子程序(内嵌子程序):
    
     创建内嵌子程序就必须用CREATE命令建立
    
    创建存储(内嵌)过程:
    
    
    CREATE [OR  REPLACE]  PROCEDURE   过程名[(参数表)]  IS | AS
     
              说明部分                        ――无 DECLARE 命令
    
            BEGIN
      
              执行部分
    
            EXCEPTION
    
              例外处理部分
    
            END;
    
    
    
    用OR  REPLACE可选项,如果过程已存在,则重建过程,利用该选项可修改已存在的过程的定义。
    
    创建内嵌过程除用CREATE命令外,其它同PL/SQL块内定义的过程结构相同
    
    内嵌过程一旦被创建后,过程的拥有者或对该过程被授执行特权的用户就可以执行它,即有权访问的任何用户的应用程序或任意ORACLE工具中调用
    
      SQL> create  or  replace  procedure   chp1 (x  in  varchar2, y  out  varchar2 ,n  in  number:=7)  is
     
            local1  varchar2(50);
    
           begin
             local1:=x|| ‘  ’||to_char(n);
    
             y:=local1;
     
           end;   
    
    运行该命令,创建内嵌过程
       SQL> declare
    
                x1  varchar2(30);
    
            begin
      
                chp1(‘hello  world’,x1);
     
                dbms_output.put_line(x1);
     
                chp1(y=>x1,x=>‘ hello world’ ,n=>12);
                dbms_output.put_line(x1);
            end;
    
    
    
    从一应用程序调用, 其调用形式:
    
    EXEC  SQL  EXECUTE
     
            BEGIN
      
              CHP1(  :str, :n);     --实参str, n 为宿主变量。
     
            END;
           
    END_EXEC;
    
    
    删除内嵌过程命令:
    DROR  PROCEDURE    过程名  
    作用:从数据库中删除一独立过程。操作者必须有权限
    
    重新编译一独立存储的过程命令
    ALTER  PROCEDURE    过程名  COMPILE
    
    
    创建内嵌函数:
    
    CREATE [OR  REPLACE] FUNCTION 函数名(参数表)
      RETURN    数据类型  IS |AS
         
         说明部分    ――无 DECLARE  语句
      
    BEGIN
     
         执行部分    ――致少有一条RETURN语句
      
    EXCEPTION
    
          例外处理部分
       
    END;
                
    
    函数参数一般采用IN参数。
    
    
    SQL> create  of  replace  function  chp2( x  varchar2 )
     
                         return  varchar2  is
    
                       begin
     
                         return ( x|| ‘ is the parameter ’);
    
                      end;
    
    函数一旦被创建后, 在当前用户的PL/SQL摸块中, 就可以在表达式中使用该函数, 或对该函数授有EXECUTE特权的其它用户也可以使用。
    
    declare
    
                value_retu   varchar2(80);
    begin
    
                value_retu:=chp2 (‘hello  word’);
     
               dbms_output.put_line(value_retu);
     
    end;
    
    
    内嵌函数必须在表达式中调用
    
     删除内嵌函数命令:
    DROP  FUNCTION  函数名
    
    重新编译一独立的内嵌函数:
     ALTER    FUNCTION    函数名  COMPILE
    
    
    过程与函数的异同:
    
    过程:
     作为 PL/SQL 语句执行;
     在规范中不包含 RETURN 子句;
     不返回任何值(只有输入/输出参数,结果集);
     可以包含 RETURN 语句,但是与函数不同,它不能用于返回值。
    
    函数
     作为表达式的一部分调用;
     必须在规范中包含 RETURN 子句;
     必须返回单个值;
     必须包含至少一条 RETURN 语句。
    

      

  • 相关阅读:
    Net基础篇_学习笔记_第十二天_面向对象继承(命名空间 、值类型和引用类型)
    Net基础篇_学习笔记_第十一天_面向对象(练习)
    js判断客户端是pc还是移动端
    swoole_table
    Master Reactor Manager Worker TaskWorker(Task)
    阻塞,非阻塞,同步,异步
    进程,线程与协程
    swoole 安装与简单应用
    laravel 简单应用 redis
    ubuntu 设置固定IP
  • 原文地址:https://www.cnblogs.com/wust221/p/3072245.html
Copyright © 2011-2022 走看看