PLSQ编程

2022-07-05 13:40:58 浏览数 (1)

PLSQ编程

流程控制:

判断语句 if

循环语句 loop exit while for

顺序语句 goto null

判断语句 if

代码语言:javascript复制
IF <布尔表达式> THEN
  PL/SQL 和 SQL语句
  END IF;
   
  IF <布尔表达式> THEN
  PL/SQL 和 SQL语句
  ELSE
  其它语句
  END IF;
   
  IF <布尔表达式> THEN
  PL/SQL 和 SQL语句
  ELSIF < 其它布尔表达式> THEN
  其它语句
  ELSIF < 其它布尔表达式> THEN
  其它语句
  ELSE
  其它语句
  END IF;

根据用户输入的用户编号,确定用户的工资等级

代码语言:javascript复制
 --根据用户输入的用户编号,确定用户的工资等级
  declare
    v_empno emp.empno%Type:=&v_empno;
    v_sal emp.sal%type;
   begin
           
     select sal into v_sal from emp where empno=v_empno;
     dbms_output.put_line(v_sal);
     if v_sal <1500 then
       dbms_output.put_line('工资等级为1级');
      elsif v_sal <3000 then 
        dbms_output.put_line('工资等级为2级');
       else
         dbms_output.put_line('工资等级为3级');
     end if;
   end;

循环语句 loop exit while for

简单循环:loop

LOOP 要执行的语句; EXIT WHEN <条件语句> /条件满足,退出循环语句/END LOOP;

代码语言:javascript复制
 --输出1--10
  declare
    v_i number :=1;
   begin
     loop 
       dbms_output.put_line(v_i);
       v_i:=v_i 1;
       exit when v_i > 10;--当满足条件的时候 结束循环
      
     end loop;
   end;

while循环:

WHILE <布尔表达式> LOOP 要执行的语句;END LOOP;

代码语言:javascript复制
  --输出1--10
  declare
    v_i number := 1;
  ​
  begin
    while v_i <= 10 loop --当满足条件的时候  执行循环
      dbms_output.put_line(v_i);
      v_i := v_i   1;
     end loop;
  end;

FOR循环(数字式循环)

FOR 循环计数器 IN [ REVERSE ] 下限 .. 上限 LOOP 要执行的语句;END LOOP;

代码语言:javascript复制
  declare 
     v_i number := 1;
  begin
    for v_i in 1 .. 10 loop
      
        dbms_output.put_line(v_i);
      end loop;
  end;
代码语言:javascript复制
  ​
  declare 
     v_i number := 1;
  begin
    for v_i in reverse 1 .. 10 loop
      
        dbms_output.put_line(v_i);
      end loop;
  end;
代码语言:javascript复制
  declare 
     v_i number := 1;
  begin
    for v_i in reverse 1 .. 10 loop
        
        if v_i = 5 then
         exit;--退出循环
        end if;
        dbms_output.put_line(v_i);
        
      end loop;
  end;

null语句

代码语言:javascript复制
  declare 
     v_i number := 1;
  begin
    for v_i in reverse 1 .. 10 loop
        
        if v_i = 5 then
          
          null;--表示什么都不做
           -- exit;退出循环
        end if;
        dbms_output.put_line(v_i);
        
      end loop;
  end;

异常处理

异常情况处理(EXCEPTION)是用来处理正常执行过程中未预料的事件

程序块的异常处理预定义的错误和自定义错误,

异常的默认处理方式:显示异常信息 并终止程序执行

三种类型的异常错误:

预定义 ( Predefined )错误

ORACLE预定义的异常情况大约有24个。对这种异常情况的处理,无需在程序中定义,由ORACLE自动将其引发。

非预定义 ( Predefined )错误

即其他标准的ORACLE错误。对这种异常情况的处理,需要用户在程序中定义,然后由ORACLE自动将其引发。用户定义(User_define) 错误

程序执行过程中,出现编程人员认为的非正常情况。对这种异常情况的处理,需要用户在程序中定义,然后显式地在程序中将其引发

异常处理的语法

代码语言:javascript复制
  异常处理部分一般放EXCEPTION
     WHEN first_exception THEN  <code to handle first exception >
     WHEN second_exception THEN  <code to handle second exception >
     WHEN OTHERS THEN  <code to handle others exception >
  END;

异常处理可以按任意次序排列,但 OTHERS 必须放在最后.

异常的分类

Oralce中的异常分为如下三类: 预定义的ORACLE数据库异常:有异常名,有错误代码,有异常信息 非预定义的ORACLE数据库异常:无异常名有错误代码,有异常信息。 用户自定义异常:违反用户自定义的业务逻辑规则,由程序主动触发。

预定义异常

代码语言:javascript复制
  declare
    v_empno emp.empno%type:=100;
    v_ename emp.ename%type;
    
  begin
    v_empno :=&v_empno;
    select ename into v_ename from emp where empno = v_empno;
    dbms_output.put_line(v_ename);
    
  end;
代码语言:javascript复制
  declare
    v_empno emp.empno%type;
    v_ename emp.ename%type;
    
  begin
    v_empno :=&v_empno;
    select ename into v_ename from emp ;
    dbms_output.put_line(v_ename);
    
  end;

非预定义异常

代码语言:javascript复制
  delete from employees where employee_id=100;
代码语言:javascript复制
  delete from dept where deptno=10;

异常处理

代码语言:javascript复制
  declare
    v_empno emp.empno%type;
    v_ename emp.ename%type;
    
  begin
    v_empno :=&v_empno;
    select ename into v_ename from emp where empno=v_empno;
    dbms_output.put_line(v_ename);
    exception
      when no_data_found then
            dbms_output.put_line('你所要查询的用户不存在');
      when too_many_rows then
           dbms_output.put_line('找到的数据过多');
          
      
      when others then
           dbms_output.put_line('程序发生错误');
    
  end;

非预定异常的处理

代码语言:javascript复制
  --删除指定部门的记录信息,以确保该部门没有员工。
  DECLARE
     v_deptno dept.deptno%TYPE :=&deptno;--10
     e_deptno_remaining EXCEPTION;
     PRAGMA EXCEPTION_INIT(e_deptno_remaining, -2292);
     /* -2292 是违反一致性约束的错误代码 */
  BEGIN
     DELETE FROM dept WHERE deptno=v_deptno;
  EXCEPTION
     WHEN e_deptno_remaining THEN 
        DBMS_OUTPUT.PUT_LINE('违反数据完整性约束!');
     WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('发生其它错误!');
  END; 

SQLCODE、SQLERRM

代码语言:javascript复制
  BEGIN
     INSERT INTO emp(empno, ename, hiredate, deptno)
           VALUES(2222, 'Jerry', SYSDATE, 20);
     DBMS_OUTPUT.PUT_LINE('插入数据记录成功!');
     INSERT INTO emp(empno, ename, hiredate, deptno)
           VALUES(2222, 'Jerry', SYSDATE, 20);
     DBMS_OUTPUT.PUT_LINE('插入数据记录成功!');
  EXCEPTION
     WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
  END;

输出结果

代码语言:javascript复制
  插入数据记录成功!
  -1---ORA-00001: 违反唯一约束条件 (SCOTT.PK_EMP)

游标

在 PL/SQL 程序中,对于处理多行记录的事务经常使用游标来实现

为了处理 SQL 语句,ORACLE 必须分配一片叫上下文( context area )的区域来处理所必需的信息,其中包括要处理的行的数目,一个指向语句被分析以后的表示形式的指针以及查询的活动集(active set)。 游标是一个指向上下文的句柄( handle)或指针。通过游标,PL/SQL可以控制上下文区和处理语句时上下文区会发生些什么事情

游标的分类

显式游标

游标定义

代码语言:javascript复制
  格式:
     CURSOR cursor_name[(parameter[, parameter]…)] IS select_statement;
     游标参数只能为输入参数,其格式为:
           parameter_name [IN] datatype [{:= | DEFAULT} expression]
      在指定数据类型时,不能使用长度约束。如NUMBER(4)、CHAR(10) 等都是错误的。

打开游标

就是执行游标所对应的SELECT 语句,将其查询结果放入工作区,并且指针指向工作区的首部,标识游标结果集合。如果游标查询语句中带有FOR UPDATE选项,OPEN 语句还将锁定数据库表中游标结果集合对应的数据行。

代码语言:javascript复制
  格式:
  OPEN cursor_name[([parameter =>] value[, [parameter =>] value]…)];

在向游标传递参数时,可以使用与函数参数相同的传值方法,即位置表示法和名称表示法。PL/SQL 程序不能用OPEN 语句重复打开一个游标。

提取游标数据

就是检索结果集合中的数据行,放入指定的输出变量中。

代码语言:javascript复制
  格式:
  FETCH cursor_name INTO {variable_list | record_variable };

对该记录进行处理;继续处理,直到活动集合中没有记录;

关闭游标

当提取和处理完游标结果集合数据后,应及时关闭游标,以释放该游标所占用的系统资源,并使该游标的工作区变成无效,不能再使用FETCH 语句取其中数据。关闭后的游标可以使用OPEN 语句重新打开。

代码语言:javascript复制
  CLOSE cursor_name;

游标的使用:

代码语言:javascript复制
  --获取emp表中所有员工的信息
  declare
    cursor c_emp is select * from emp;--声明一个游标;
    o_emp emp%rowtype;
    
    begin 
      open c_emp;--打开游标
      fetch c_emp into o_emp;--提取数据
            dbms_output.put_line(o_emp.empno||'--'||o_emp.ename);
     fetch c_emp into o_emp;--提取数据
            dbms_output.put_line(o_emp.empno||'--'||o_emp.ename);
      close c_emp; --关闭游标
      
      
    end;
  ​

使用循环提取数据

代码语言:javascript复制
  --获取emp表中所有员工的信息
  declare
    cursor c_emp is select * from emp;--声明一个游标;
    o_emp emp%rowtype;
    v_s boolean;
    
    begin 
      open c_emp;--打开游标
      if c_emp%isopen then
        loop
          fetch c_emp into o_emp;--提取数据
               
            exit when c_emp%NOTFOUND;
            dbms_output.put_line(c_emp%rowcount||'--'||o_emp.empno||'--'||o_emp.ename);
        end loop;
      end if;
      close c_emp; --关闭游标
    end;
  ​

游标属性

%FOUND 布尔型属性,当最近一次读记录时成功返回,则值为TRUE; %NOTFOUND 布尔型属性,与%FOUND相反; %ISOPEN 布尔型属性,当游标已打开时返回 TRUE; %ROWCOUNT 数字型属性,返回已从游标中读取的记录数。

使用for循环来提取游标数据

PL/SQL语言提供了游标FOR循环语句,自动执行游标的OPEN、FETCH、CLOSE语句和循环语句的功能;当进入循环时,游标FOR循环语句自动打开游标,并提取第一行游标数据,当程序处理完当前所提取的数据而进入下一次循环时,游标FOR循环语句自动提取下一行数据供程序处理,当提取完结果集合中的所有数据行后结束循环,并自动关闭游标。格式: FOR index_variable IN cursor_name[value[, value]…] LOOP — 游标数据处理代码 END LOOP;其中: index_variable为游标FOR 循环语句隐含声明的索引变量,该变量为记录变量,其结构与游标查询语句返回的结构集合的结构相同。在程序中可以通过引用该索引记录变量元素来读取所提取的游标数据,index_variable中各元素的名称与游标查询语句选择列表中所制定的列名相同。如果在游标查询语句的选择列表中存在计算列,则必须为这些计算列指定别名后才能通过游标FOR 循环语句中的索引变量来访问这些列数据

代码语言:javascript复制
  --获取emp表中所有员工的信息
  declare
    cursor c_emp is select * from emp;--声明一个游标;
    o_emp emp%rowtype;
    v_s boolean;
    
    begin 
      for o_emp in c_emp loop
        dbms_output.put_line(o_emp.empno||'----'||o_emp.ename);
      end loop;
        
    end;
  ​

带参的游标

代码语言:javascript复制
  declare 
     s number :=2000;
    cursor  cc_emp(v_sal number default 800) is select * from emp where sal > v_sal;
    
    begin
      ---for oo_emp in cc_emp(1000) loop--位置传值法
      for oo_emp in cc_emp(v_sal =>s) loop--名称传值法
        dbms_output.put_line(oo_emp.ename||'----'||oo_emp.sal);
       end loop;
      
    end;

隐式游标

而对于非查询语句,如修改、删除操作,则由ORACLE 系统自动地为这些操作设置游标并创建其工作区,

这些由系统隐含创建的游标称为隐式游标,隐式游标的名字为SQL

隐式游标属性 SQL%FOUND 布尔型属性,当最近一次读记录时成功返回,则值为true; SQL%NOTFOUND 布尔型属性,与%found相反; SQL %ROWCOUNT 数字型属性, 返回已从游标中读取得记录数; SQL %ISOPEN 布尔型属性, 取值总是FALSE。SQL命令执行完毕立即关闭隐式游标。

–删除EMP 表中某部门的所有员工,如果该部门中已没有员工,则在DEPT 表中删除该部门。

代码语言:javascript复制
  declare
         v_deptno myemp.deptno%type;
     
  begin    
         v_deptno :=&v_deptno;
         delete from myemp where deptno = v_deptno;
         if sql%notfound then
           delete from mydept where deptno = v_deptno;
           
         end if;
       
   end;

PLSQL程序单元

是数据库中命名的PL/SQL块,作为数据库对象保存在数据库中。主要有四类:过程:执行特定操作,无返回值;函数:执行复杂操作,有返回值包:逻辑上相关的过程和函数的组合体触发器:事件触发,执行相应的操作

ORACLE 提供可以把PL/SQL 程序存储在数据库中,并可以在任何地方来运行它。这样就叫存储过程或函数。

过程和函数的唯一区别是函数总向调用者返回数据,而过程则不返回数据。

存储过程的参数特性:

函数

函数将处理从程序的调用部分传递给它的信息,然后返回单个值。信息通过称为参数的特殊标识符传递给函数,然后通过RETURN语句返回。

代码语言:javascript复制
  CREATE [OR REPLACE] FUNCTION function_name
  [(argment [ { IN| IN OUT }] type,
      argment [ { IN | OUT | IN OUT } ] type]
  RETURN return_type 
  { IS | AS }
  <类型.变量的说明> 
  BEGIN
  FUNCTION_body
  EXCEPTION
  其它语句
  END;
  ​

带参函数

代码语言:javascript复制
  CREATE OR REPLACE Function sumSalFun(v_deptno in number,--输入参数 接收调用者传递的数据
                                       v_allsal out number--输出参数 传递给调用者的数据
                                       ) return number is
    v_sumsal number;--返回值  函数执行结束之后 返回给调用者的结果
  begin
    select sum(sal) into v_sumsal from emp where deptno = v_deptno;
  ​
    v_allsal := 200;
    return v_sumsal;
  end;

函数传参

  1. 位置表示法
代码语言:javascript复制
  declare 
    v_result number;
    v_outpara number;
  begin 
    v_result := SUMSALFUN(20,v_outpara);--位置表示法  按照函数定义时的参数的声明位置 来在对应的位置 传递对应的参数
    
    dbms_output.put_line(v_result||'---'||v_outpara);
    
  end;

2 .名称表示法

代码语言:javascript复制
  declare 
    v_result number;
    v_outpara number;
    vv_deptno number :=20;
  begin 
    v_result := SUMSALFUN(v_allsal=>v_outpara,v_deptno => vv_deptno);--名称表示法  按照函数定义时的参数的声明名称 给对应的名称 传递对应的参数
    
    dbms_output.put_line(v_result||'---'||v_outpara);
    
  end;

3 混合表示法

代码语言:javascript复制
  declare 
    v_result number;
    v_outpara number;
    vv_deptno number :=20;
  begin 
    v_result := SUMSALFUN(20,v_allsal => v_outpara);--名称表示法  按照函数定义时的参数的声明名称 给对应的名称 传递对应的参数
    
    dbms_output.put_line(v_result||'---'||v_outpara);
    
  end;

存储过程

无参存储过程

代码语言:javascript复制
  CREATE  OR  REPLACE  PROCEDURE  过程名  [(parameter,...)]
  IS
      定义变量
  Begin
      Plsql程序
  End;

执行:

在sql窗中:

代码语言:javascript复制
  begin
    pro1();
  end;

命令窗口:

代码语言:javascript复制
  exec pro1();

带参存储过程 输入参数

代码语言:javascript复制
  declare
    v_empno number:=&v_empno;
    v_ename varchar2(50) :=&v_ename;
    v_sal number :=&v_sal;
    v_job varchar2(50) :=&v_job;
  begin
    --pro1(v_empno,v_ename,v_sal,v_job);--位置表示法
   -- pro1(v_empno=>v_empno,v_ename=>v_ename,v_sal=>v_sal,v_job=>v_job);--名称表示法
   pro1(v_empno,v_ename,v_sal=>v_sal,v_job=>v_job);--在混合表示法中,位置标示法必须放在前边,而且在出现名称标示法之后,不能再穿插位置标示法
  end;
  SELECT * FROM MYEMP;
代码语言:javascript复制
  create or replace procedure pro2(v_deptno in out number,--输入输出参数
                                   v_empnum out number) is
  begin
    select count(*), sum(sal)
      into v_empnum, v_deptno
      from myemp
     where deptno = v_deptno;
  ​
  end pro2;

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/111275.html原文链接:https://javaforall.cn

0 人点赞