zoukankan      html  css  js  c++  java
  • 9.pl/sql 子程序

       pl/sql 可以分为命名块和匿名块。下面将介绍pl/sql 命名块,命名块没有匿名块的限制,他们可以存储到数据库中,可以被其他的块调用,不需要在每次执行时都重复编译。

    1.创建过程的示例
    create or replace procedure newdept(
       p_deptno dept.deptno%type;               -- 部门编号
       p_name dept.dname%type;                  -- 部门位置
       p_loc  dept.loc%type
    )
    as
       v_deptcount number;                      -- 保存是否存在员工编号
    begin
       select count(*) into v_deptcount from dept 
        where deptno=p_deptno;                  -- 查询在deptno 表中是否存在部门编号
       if v_deptcount>0                         -- 如果存在相同的员工信息
       then
          raise_application_error(-2002,'出现了相同的员工信息');
       end if;
       insert into dept(deptno,dname,loc)
          values(p_deptno,p_dname,p_loc);   --插入记录
       commit;   --提交事务
             
    end;
    2.调用1 过程示例
    begin
       newdept(10,'成本科','深圳');
    exception
       when others then
          dbms_output.put_line('产生了错误:'||sqlerrm);   
    end;
    3.创建newdept 过程
    create or replace procedure newdept(
       p_deptno in number,                 -- 部门编号
       p_dname in varchar2,                -- 部门名称
       p_loc    in varchar2                -- 位置
       
    )
    as
       v_deptcount  number(4);             -- 保存是否存在员工编号
       e_duplication_dept exception;
    begin
       select count(*) into v_deptcount from dept 
        where deptno=p_deptno; --查询在dept 表中是否存在的部门编号
       if v_deptcount >0                   -- 如果存在相同的员工记录
       then                                -- 抛出异常
          raise e_duplication_dept;
       end if;
       insert into dept(deptno,dname,loc)
          values(p_deptno,p_name,p_loc);  -- 插入记录
       commit;                            -- 提交事务
       exception 
          when e_duplication_dept then
             rollback;
             raise_application error(-20002,'出现了相同的员工信息');
             
    end;
    4.getraisedsalary 函数示例
    create or replace function getraisedsalary(p_empno emp.empno%type)
    return number 
    is
       v_job emp.job%type; -- 职位变量
       v_sal emp.sal%type; -- 薪资变量
       v_salaryratio number(10.2);-- 调薪比率
    begin
       --获取员工表中的薪资信息
       select job,sal into b_job,v_sal from emp where empno=v_empno;
       case v_job
          when '职员' then
             v_salaryratio :=1.09;
          when '销售人员' then
             v_salaryratio :=1.11;
          when '经理' then
             v-salaryratio :=1.18;
          else
             v_salaryratio :=1;
        end case;
        if v_salaryratio <>1                       -- 如果有调薪的可能   
        then 
           return round(v_sal *v_salaryratio,2);   -- 返回调薪后的薪资
        else
           return v_sal;                           -- 否则不返回薪资  
        end if;
        exception
           when no_data_found then
              return 0;                            -- 如果没有找到员工共记录,则返回0                           -- 如果没有找到员工记录,则返回0
           
    end getraisedsalary;
    5.调用4函数
    declare
       v_raisedsal number(10,2);    -- 定义保存调薪记录的临时文件
    begin
       -- 调用函数获取调薪后的记录
       dbms_output.put_line('7369员工调薪记录:'getraisedsalary(7369));
       v_raisedsal:=getraisedsalary(7521);
       dbms_output.pUt_line('7521员工调薪记录:'||getraisedsalary(7521));
    end;
    6.在过程中使用return语句示例
    create or replace procedure raisesalary(
    p_)rmpno emp.mempno%type     -- 员工编号参数
    as
       v_job emp.job%type;   -- 局部的职位变量
       v_sal emp.sal%type;   -- 局部的薪资变量
    begin
       --  查询员工信息
       select job,sal into v_job,v_sal from emp where empno=p_empno;
       if v_job<>'职员' then           -- 仅为职员加薪
          return;                      -- 如果不是职员,则退出
       elsif v_sal >3000 then          -- 如果职员薪资大于3000 则退出
          return;
       else
       -- 否则更新薪资记录
          update emp set sal= round(sal*1.12,2) where empno=p_empno;
       end if;
    exception
       when no_data_found then        -- 异常处理
          dbms_output.put_line('没有找到员工记录'); 
    end raisesalary;
    7.insertdept  过程示例
    create or replace procedure insertdept(
       p_deptno number,    --定义形参
       p_dname varchar2,
       p_loc varchar2
    )
    as
       v_count number(10);
    begin
       select count(deptno) into v_count from dept where deptno=p_deptno;
       if v_count >1 then
          raise_application_error(-20001,'数据库中存在相同名称的部门编号!');
       end if;
       insert into dept values(p_deptno,p_name,p_loc);-- 在过程体中使用形参
       commit;
       
    end;
    8.使用in模式
    create or replace procedure insertdept(
       p_deptno in number:=55,            --定义形式参数,并赋初值
       p_dname in varchar2,
       p_loc in varchar2
    )
    as
       v_count number(10);
       
    begin
       -- p_dname:='市场策略部';    -- 错误,不能对in模式参数进行赋值
       select count(deptno) into v_count from dept where deptno=p_deptno;
       if v_count>1 then 
    
          raise_application_error(-20001,'数据库中存在相同名称的部门编号');
       end if;
       insert into dept values(p_deptno,p_name,p_loc);-- 在过程体中使用形式参数
       commit;
    end;
    -- 调用
    begin
       insertdept(55,'秦云不','西北');
    end;
    9.使用out 模式
    create or replace procedure OutraiseSalary(
       p_enpno in number,
       p_raisedSalary out number    -- 定义一个员工加薪后的子女西的输出变量
       
    )
    as
       v_sal number(10,2);          -- 定义本地局部变量
       v_job varchar2(10);
    begin
       p_raisedSalary:=0;           -- 变量赋初值
       select sal,job into v_sal,v_job from emp where empno=p_empno;-- 查询员工信息
       if v_job='职员' then   -- 仅对职员加薪
          p_raisedSalary :=v_sal*1.12; -- 对out 模式的参数进行赋值时合法的
          update emp set sal=p_raisedSalary where empno=p_empno;
       else
       p_raisedSalary :=v_sal;      -- 否则赋原先的薪资值
     end if;
    exception 
       when no_data_found then      --异常处理语句块
       dbms_output.put_line('没有找到该员工的记录');
    end;
    --调用
    declare
       v_raisedsalary number(10,2);         -- 定义一个变量保存数据值
    begin
       v_ralsedsalary:=100;                 -- 这个赋值在传入到outraisesalary后呗hulue
       outRaiseSalary(7369,v_raisedsalary); -- 调用函数
       dbms_outpuit.put_line(v_raisedsalary);             -- 显示输出参数的值
           
    10.使用 inout 模式
    create or replace procedure calcraisedsalary(
       p_job in varchar2,
       p_cakary in out number                   -- 定义输入输出参数
    )
    as
       v_sal number(10,2);                      -- 保存调整后的薪资值
    begin
       if p_job='职员' then                    -- 根据不同的job进行薪资的调整
          v_sal:=p_salary*1.12;
       elsif p_job='销售人员' then
          v_sal:=p_salary*1.18;
       elsif p_job='经理' then
          v_sal :=p_salary*1.19;
       else
          v_sal:=p_salary;
       end if;
       p_salary:=v_sal;                        --将调整后的结果赋给输入/输出参数
       
       
    end;
    -- 调用
    declare
       v_sal number(10,2);                 --薪资变量
       v_job varchar2(10);                -- 职位变量
    begin
       select sal,job into v_sal,v_jon from emp where empno='7369';   --获取薪资和职位信息
       calcraisedsalary(v_job,v_sal);                       -- 计算调薪
       dbms_output.Put_line('计算后的调整薪水为:'||v_sal);-- 获取调薪后的结果
    end;
    11 使用%type 定义形式参数
    create or replace procedure calcraisedsalarywithtype(
       p_job in emp.job%type,
       p_salary in out emp.sal%type   --定义输入/输出参数
       
    )
    as
    v_sal  number(10,2); -- 保存调整后的薪资值
    begin                       
       if p_job ='职员'  then      --根据不同的job 进行薪资的调整
          v_sal:=p_salary*1.12;
       elsif p_job='销售人员' then
          v_sal:=p_salary**1.18;
       elsif p_job='经理' then
          v_sal:=p_salary*1.19;
       else
          v_sal:=p_salary;
       end if;
       p_salary:=v_sal;             -- 将调整后的结果给输入/输出参数
    end;
    12. 指定形式参数的默认值
    create or replace procedure newdeptwithdefault(
       p_deptno dept.deptno%type default 57,        -- 部门编号
       p_dname  dept.dname%type:='管理部',          -- 部门名称
       p_loc    dept.loc%type default '江苏'        -- 位置
    )
    
    as
       v_deptcount number;                         -- 保存是否存在员工编号
    begin
       select count(*) into v-deptcount from dept where deptno=p_deptno;   -- 查询在dept表中时否存在部门编号
       if v_deptcount>0                           -- 如果存在相同的员工记录
       then
          raise_application_error(-20002,'出现了相同的员工记录');
       end if;
       insert into dept(deptno,dname,loc)
          values(p_deptno,p_dname,p_loc);   --插入记录
          
    end;
    13.nocopy 使用示例
    declare
       type emptabtyp is table of emp%rowtype;  -- 定义嵌套表类型
       emp_tab emptavtyp :=emptabtyp(null);     -- 定义一个空白的嵌套表变量
       t1 number(5);                            -- 定义保存时间的临时变量
       t2 number(5);
       t3 number(5);
       procedure get_time(t out number)         -- 获取当前时间
       is
       begin
          select to_char(sysdate,'ssss')
          into t
          from dual;     -- 获取从午夜到当前的秒数
       end;
       procedure do_nothing1 (tab in out emptabtyp)  --  定义一个空白的过程,具有in out 参数
       is
       begin
            null;
       end;
       begin
       select * into rmp_tab(1) from rmp where empno=7788;-- 查询emp表中的员工,插入到emp_tab第一个记录
       emp_tab.extend(900000,1);    -- 复制第一个元素n次
       get_time(t1);                -- 获取当前时间
       do_nothing1(emp_tab);        -- 执行不带nocopy的过程
       get_time(t2);                -- 获取当前时间
       do_nothings(emp_tab);        -- 执行带nocopy的过程
       get_time(t3);                -- 获取当前时间
       dbms_output.put_line('调用所花费的时间(秒)');
       dbms_output.put_line('------------------');
       dbms_output.put_line('不带nocopy的调用:'||to_char(t2-t1));
       dbms_output.put_line('带nocopy的调用:'||to_char(t3-t2));
     end;   
    14.  定义可被sql语句调用的子程序
    create or replace function getempdept(
       p_empno emp.empno%type
       
    )return varchar2  -- 参数必须是Oracle数据库类型
    as
    v_dname dept.dname%type;
    begin
         select b.dname into v_dname from emp a,dept b where a.deptno=b.deptno and a.empno=p_empno;
         return v_dname;-- 查询数据库,获取部门信息
         exception 
         when no_data_found then
         return null;   -- 如果查询不到数据,返回null
    end;
    15. 使用嵌套子程序示例
    create or replace function getraisedsalary_subprogram(p_empno emp.empno%type)
    return number
    is
       v_salaryratio number(10,2);   -- 调薪比率
       v_sal  emp.sal%type;          -- 薪资变量
       -- 定义内嵌子函数,返回薪资和调薪比率
    function getratio(p_sal out number) return number is
       n_job emp.job%type;           -- 职位变量
       n_salaryratio number(10,2);   -- 调薪比率
    
    begin
       -- 获取员工表中的薪资信息
       select job,sal into n_job,p_sal form emp where empno=p_empno;
       case n_job
          when '职员' then
             n_salaryratio :=1.09;
          when '销售问题' then
             n_salaryratio :=1.11;
          when '经理' then
             n_salaryratio :=1.18;
          else
             n_salaryratio :=1;
             
    end;
    begin
       v_salaryratio:=getratio(v_sal);   --调用嵌套函数,获取挑衅比率和员工薪资
       if v_salaryratio >1
       then
          return round(v_sal * v_salaryratio,2);  - -返回调薪后的薪资
       else
       return v_sal;    -- 否则不返回薪资
    end if;
    exception
    when no_data_found then
    return 0;   --如果没有找到员工记录,则返回0
    end;
    16.嵌套子程序互调用示例
    declare
       v_sal binary_integer:=5;
       procedure a(p_counter in out binary_integer) is   -- 声明嵌套子程序A
       begin
         dbms_output.put_line('A('||p_counter||')');
         if p_counter>0 then
         b(p_counter);   --在嵌套子程序中调用B
         p_counter:=p_counter-1;
      end if;
    end A;
    procedure b(p_counter in out binary_integer) is -- 声明嵌套子程序B
    begin
        dbms_output.put_line('b('||p_counter||')');
        p_counter:=P_counter-1;
        a(p_counter);                                 -- 在嵌套子程序中调用A
     end b;
     begin
         b(v_val);    --调用嵌套子程序b
    end;
    17. 使用前向声明及逆行互调用
    declare
       v_sal binary_integer:=5;
       procedure b(p_counter in out binary_integer);-- 前向声明嵌套子程序B
       procedure a(p_counter in out binary_integer) is   -- 声明嵌套子程序 a
       begin
           dbms_output.put_line('a('||p_counter||')');
           if p_counter >0 then
           b(p_counter);                             -- 在嵌套子程序中调用b
           
           p_counter:=p_counter-1;
       end if;
    end a;
    procedure b(p_counter in out binary_integer) is  -- 声明嵌套子程序b
    begin
       dbms_output.put_line('b('||p_counter||')');
       p_counter:=p_counter-1;
       a(p_counter);                                  -- 在嵌套子程序中调用A
      end b;
     begin
     b(v_sal);     -- 调用嵌套子程序b
     end;
     
    18.嵌套子程序重载示例
    declare
       procedure getsalary(p_empno in number) is     -- 带一个参数的过程
       begin
           dbms_output.put_line('员工编号为:'||p_empno);
       end;
       procedure getsalary(p_empname in varchar2) is     --重载的过程
       begin
           dbms_output.put_line('员工名称为:'||p_empname);
       end;
       procedure getsalary(p_empno in number,p_empname in varchar2) is  -- 升薪的过程
       begin
           dbms_output.put_line('员工编号为:'||p_empno||'员工名称为'||p_empnme);
       end;
       begin
           getsalary(7369);    -- 调用重载方法
           getsalsry('史密斯');
           getsalary(7369,'史密斯');
       end;
    19.自制事务使用示例
    declare
       procedure testAutonomous(p_empno number) as
          pragma autonomous_transaction;    --标记为自治事务
       begin
           -- 现在过程中是自治的事务,主事务被挂起
       insert into emp_history select * from emp where empno=p_empno;
       commit;   -- 提交自治事务,不影响主事务
       end testautonomous;
    begin
        -- 主事务开始执行
        insert into emp_history(empno,ename,sal) values(1011,'测试','1000');
        testautonomous(7369);    --主事务挂起,开始自治事务
        rollvack;           --回滚主事务
        end;
    20. plsql 实现递归阶乘
    declare
       v_result integer;
       function fac(n positive)
          return integer is   -- 阶乘的返回结果
       begin
           if n=1 then         -- 如果n=1  则终止条件
           dbms_output.put('11!=1*0');
           return 1;
       else
          dbms_output.put_line(n||'!='||n||'*');
       return n*fac(n-1);       --否则递归调用自身
    end if;
    end fac;
    begin
        v_result :=fac(10);   ---调用阶乘函数
        dbms_output.put_line('结果是:'||v_result);-- 输出阶乘结果
    end;
    21.使用递归查询职员列表示例
    declare
       procedure find_staff(mgr_no number, tier number :=1)
       is
          boss_name varchar2(10);   -- 定义老板的名称
          cursor c1(boss_no number)   --定义游标来查询emp表中当前编号下的员工列表
          is
             select empno,ename
             from emp
             where mgr=boss_no;
       beign
          select ename into boss_name form emp
          where empno=mgr_no;    -- 获取管理者名称
          if tier =1   -- 如果tier 指定1 ,表示从底层开始查询
          then
          insert into staff
          values(boss_name ||'是老板');   -- 因为第一层是老板,下面才是经理
       end if;
       for ee in c1(mgr_no)          --通过游标for 循环向staff 表中插入员工信息
       loop
          insert into staff
                values(boss_name
                        ||'管理'
                        ||ee.ename
                        ||'在层次'
                        ||to_char(tier));
         find_staff (ee.empno.tier+1);   --在游标中,递归调用下层的员工列表
      end loop;
      commit;
    end find_staff;
    begin
        find_staff(7839);                    -- 查询7839管理下的与纳贡的列表和层次结构
    end;
    22.子程序依赖性示例
    create or replace procedure testdependence as
    begin
        -- 向emp表插入测试数据
        insert into emp(empno,ename,sal) values(1011,'测试',1000);
        testsubprog(7369);
        rollback;
    end;
    -- 被另外一个过程调用,用来向emp_history 表插入数据
    create or replace procedure testsubprog(p_empno number) as
    begin
        insert into emp_history select *from emp where empno=p_empno;
    end testsubprog;
  • 相关阅读:
    Python 3基础教程32-正则
    Python 3基础教程31-urllib模块
    Python 3基础教程30-sys模块
    Python 3基础教程29-os模块
    Python 3基础教程28-内置函数
    Python 3基础教程27-字典
    Python 3基础教程26-多行打印
    Python 3基础教程24-读取csv文件
    Python 3基础教程25-异常处理
    Python 3基础教程23-多维列表
  • 原文地址:https://www.cnblogs.com/etllearn/p/15166680.html
Copyright © 2011-2022 走看看