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;
原文地址:https://www.cnblogs.com/etllearn/p/15166680.html