zoukankan      html  css  js  c++  java
  • Oracle学习(十一):PL/SQL

    版权声明:本文为博主原创文章。未经博主同意不得转载。 https://blog.csdn.net/v123411739/article/details/30231659

    1.知识点:能够对照以下的录屏进行阅读

    PL/SQL程序结构
    declare
          说明部分    (变量说明,光标申明,例外说明 〕
    begin
          语句序列   (DML语句〕… 
    exception
          例外处理语句   
    End;
    /
    ------------------------------------------------------------------
    --第一个PL/SQL程序:HelloWorld
    set serveroutput on	--假设要在屏幕上输出信息,须要将serveroutput开关打开
    declare
      --变量的说明
    begin
       --程序体
       --程序包package
       dbms_output.put_line('Hello World');
    end;
    /
    ------------------------------------------------------------------
    
    --引用型变量: 查询并打印7839的姓名和薪水
    
    set serveroutput on
    
    declare 
      --定义变量,
      pename emp.ename%type;		--将pename的类型设置为emp表中ename的类型
      psal   emp.sal%type;	--将psal的类型设置为emp表中sal的类型
    
    begin
    
      --查询: 
      --ename,sal into pename,psal:将查询的ename,sal分别赋值给pename,psal按顺序赋值
      select ename,sal into pename,psal from emp where empno=7839;
      
      --打印
      dbms_output.put_line(pename||'的薪水是'||psal);
    
    end;
    /
    ------------------------------------------------------------------
    
    --记录型变量 查询并打印7839的姓名和薪水
    
    set serveroutput on
    
    declare 
      --定义变量,代表一行
      emp_rec emp%rowtype;
    begin
      --得到一行,赋值给emp_rec
      select * into emp_rec from emp where empno=7839;
    
      dbms_output.put_line(emp_rec.ename||'的薪水是'||emp_rec.sal);
    
    end;
    /
    ------------------------------------------------------------------
    --if语句:推断用户输入的数字
    
    set serveroutput on
    
    /*
    1.提示信息
    2. 接收键盘输入
    num 是一个地址值
    
    SQL优化: num绑定变量(尽量使用绑定变量)
    select * from emp where deptno=10;  --> 运行计划
    select * from emp where deptno=20;  --> 运行计划
    -->
    select * from emp where deptno=#
    
    */
    accept num prompt '请输入一个数字';
    
    declare
      --变量保存输入的数字
      pnum number  := #
    begin
      --推断
      if pnum = 0 then
        dbms_output.put_line('您输入的是0');
      elsif pnum = 1 then
        dbms_output.put_line('您输入的是1');
      elsif pnum = 2 then
        dbms_output.put_line('您输入的是2');
      else
        dbms_output.put_line('其它数字');
      end if;    
    end;
    /
    ------------------------------------------------------------------
    --循环: 打印1~10,有3中方法。见下图
    
    set serveroutput on
    
    declare
      pnum number := 1;	--给pnum赋值1,pnum类型为number
    begin
      loop
        --退出:成立退出,不成立循环
        exit when pnum > 10;
        
        --隐式转换。number转varchar2
        dbms_output.put_line(pnum);
        
        pnum := pnum + 1;
    
      end loop;
    end;
    /
    ------------------------------------------------------------------
    
    光标(Cursor)==ResultSet
    
    说明光标语法:
    CURSOR  光标名  [ (參数名  数据类型[,參数名 数据类型]...)]
          IS  SELECT   语句;
    用于存储一个查询返回的多行数据
    比如:
    cursor c1 is select ename from emp;
    打开光标:      open c1;    (打开光标运行查询)
    取一行光标的值:fetch c1 into pjob; (取一行到变量中)
    关闭光标:      close  c1;(关闭游标释放资源)
    注意: 上面的pjob必须与emp表中的job列类型一致:
    定义:pjob emp.empjob%type;
    ------------------------------------------------------------------
    --光标: 使用游标查询员工姓名和工资。并打印
    
    /*
    光标的3个属性:
    %isopen 是否被打开:打开true,关闭false;
    %rowcount 行数
    %notfound 是否有值:没有值true,有值false;
    */
    
    set serveroutput on
    
    declare
      --光标
      cursor cemp is select ename,sal from emp;
      pename emp.ename%type;		--将用来接收的变量类型设置为和查询的类型同样
      psal   emp.sal%type;	
    begin
      open cemp;		--打开光标运行查询
      loop
        --从集合中取值
        fetch cemp into pename,psal;
        --光标中没有值时退出
        exit when cemp%notfound;
        
        dbms_output.put_line(pename||'的薪水是'||psal);
    
      end loop;
      close cemp;
    end;
    /
    ------------------------------------------------------------------
    --光标练习:给员工涨工资  总裁1000 经理800 其它400
    --光标同一时候能打开的最大数量默觉得300个
    /*
    SQL> show parameters cursor
    
    NAME                                 TYPE        VALUE
    ------------------------------------ ----------- --------
    cursor_sharing                       string      EXACT
    cursor_space_for_time                boolean     FALSE
    open_cursors                         integer     300
    session_cached_cursors               integer     20
    
    */
    set serveroutput on
    declare
      --光标代表员工
      cursor cemp is select empno,job from emp;
      pempno emp.empno%type;
      pjob   emp.job%type;
    begin
      open cemp;
      loop
        fetch cemp into pempno,pjob;
        exit when cemp%notfound;
        
        --推断
        if pjob = 'PRESIDENT' then update emp set sal=sal+1000 where empno=pempno;	--总裁涨1000
          elsif pjob = 'MANAGER' then update emp set sal=sal+800 where empno=pempno; --经理涨800
          else update emp set sal=sal+400 where empno=pempno;	--其它涨400
        end if;
      end loop;
      close cemp;
      
      --提交: 隔离级别
      commit;
      
      dbms_output.put_line('完毕');
    end;
    /
    ------------------------------------------------------------------
    --带參数的光标:查询某个部门的员工姓名 
    
    set serveroutput on
    
    declare
      --定义一个带參数的光标
      cursor cemp(pdno number) is  select ename from emp where deptno=pdno;
      pename emp.ename%type;
    begin
      open cemp(20);	--打开光标,并传递參数
      loop
        fetch cemp into pename;
        exit when cemp%notfound;
        
        dbms_output.put_line(pename);
    
    
      end loop;
      close cemp;
    end;
    /
    ------------------------------------------------------------------
    Oracle的异常处理
    1.系统定义例外
    No_data_found    (没有找到数据)
    Too_many_rows          (select …into语句匹配多个行) 
    Zero_Divide   ( 被零除)
    Value_error     (算术或转换错误)
    Timeout_on_resource      (在等待资源时发生超时)
    
    --举例 Zero_Divide   ( 被零除)
    
    set serveroutput on
    declare
      pnum number;
    begin
    
      pnum := 1/0;
    
    exception
      when Zero_Divide then dbms_output.put_line('1: 0不能做被除数');
                            dbms_output.put_line('2: 0不能做被除数');
      when Value_error then dbms_output.put_line('算术错');
      when others then dbms_output.put_line('其它例外');
    end;
    /
    
    用户自己定义的例外
    --自己定义例外: 查询50号部门的员工姓名
    
    set serveroutput on
    
    declare
      cursor cemp is select ename from emp where deptno=50;
      pename emp.ename%type;
      
      --自己定义例外
      no_emp_found exception;
    begin
      open cemp;
      --取一个员工
      fetch cemp into pename;
      if cemp%notfound then 
        raise no_emp_found;
      end if;
    
    /*
      if cemp%isopen then 
        close no_emp_found;
      end if;
    */
      close cemp;
      
    exception 
      when no_emp_found then dbms_output.put_line('没有找到员工');
      when others then dbms_output.put_line('其它例外');
      
    end;
    /



    图:循环的3种写法,文中採用右上角的方法。

    2.在Sqlplus下实际运行的结果录屏

    SQL> --第一个PL/SQL程序:HelloWorld
    SQL> set serveroutput on	--假设要在屏幕上输出信息,须要将serveroutput开关打开
    SQL> declare
      2    --变量的说明
      3  begin
      4     --程序体
      5     --程序包package
      6     dbms_output.put_line('Hello World');
      7  end;
      8  /
     
    Hello World
     
    PL/SQL procedure successfully completed
     
    SQL> 
    SQL> --引用型变量: 查询并打印7839的姓名和薪水
    SQL> set serveroutput on
    SQL> declare
      2    --定义变量,
      3    pename emp.ename%type;		--将pename的类型设置为emp表中ename的类型
      4    psal   emp.sal%type;	--将psal的类型设置为emp表中sal的类型
      5  
      6  begin
      7  
      8    --查询:
      9    --ename,sal into pename,psal:将查询的ename,sal分别赋值给pename。psal按顺序赋值
     10    select ename,sal into pename,psal from emp where empno=7839;
     11  
     12    --打印
     13    dbms_output.put_line(pename||'的薪水是'||psal);
     14  
     15  end;
     16  /
     
    KING的薪水是5000
     
    PL/SQL procedure successfully completed
     
    SQL> 
    SQL> -记录型变量 查询并打印7839的姓名和薪水
    SQL> set serveroutput on
    SQL> declare
      2    --定义变量,代表一行
      3    emp_rec emp%rowtype;
      4  begin
      5    --得到一行,赋值给emp_rec
      6    select * into emp_rec from emp where empno=7839;
      7  
      8    dbms_output.put_line(emp_rec.ename||'的薪水是'||emp_rec.sal);
      9  
     10  end;
     11  /
     
    KING的薪水是5000
     
    PL/SQL procedure successfully completed
     
    SQL> 
    SQL> --if语句:推断用户输入的数字
    SQL> set serveroutput on
    SQL> /*
      2  1.提示信息
      3  2. 接收键盘输入
      4  num 是一个地址值
      5  
      6  SQL优化: num绑定变量(尽量使用绑定变量)
      7  select * from emp where deptno=10;  --> 运行计划
      8  select * from emp where deptno=20;  --> 运行计划
      9  -->
     10  select * from emp where deptno=#
     11  
     12  */
     13  accept num prompt '请输入一个数字';
    SQL> declare
      2    --变量保存输入的数字
      3    pnum number  := #
      4  begin
      5    --推断
      6    if pnum = 0 then
      7      dbms_output.put_line('您输入的是0');
      8    elsif pnum = 1 then
      9      dbms_output.put_line('您输入的是1');
     10    elsif pnum = 2 then
     11      dbms_output.put_line('您输入的是2');
     12    else
     13      dbms_output.put_line('其它数字');
     14    end if;
     15  end;
     16  /
     
    您输入的是2
     
    PL/SQL procedure successfully completed
     
    SQL> 
    SQL> --循环: 打印1~10
    SQL> set serveroutput on
    SQL> declare
      2    pnum number := 1;	--给pnum赋值1,pnum类型为number
      3  begin
      4    loop
      5      --退出:成立退出,不成立循环
      6      exit when pnum > 10;
      7  
      8      --隐式转换,number转varchar2
      9      dbms_output.put_line(pnum);
     10  
     11      pnum := pnum + 1;
     12  
     13    end loop;
     14  end;
     15  /
     
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    PL/SQL procedure successfully completed
     
    SQL> 
    SQL> -光标: 使用游标查询员工姓名和工资。并打印
    SQL> /*
      2  光标的3个属性:
      3  %isopen 是否被打开:打开true,关闭false;
      4  %rowcount 行数
      5  %notfound 是否有值:没有值true,有值false。
      6  */
    SQL> set serveroutput on
    SQL> declare
      2    --光标
      3    cursor cemp is select ename,sal from emp;
      4    pename emp.ename%type;		--将用来接收的变量类型设置为和查询的类型同样
      5    psal   emp.sal%type;
      6  begin
      7    open cemp;		--打开光标运行查询
      8    loop
      9      --从集合中取值
     10      fetch cemp into pename,psal;
     11      --光标中没有值时退出
     12      exit when cemp%notfound;
     13  
     14      dbms_output.put_line(pename||'的薪水是'||psal);
     15  
     16    end loop;
     17    close cemp;
     18  end;
     19  /
     
    SMITH的薪水是800
    ALLEN的薪水是1600
    WARD的薪水是1250
    JONES的薪水是2975
    MARTIN的薪水是1250
    BLAKE的薪水是2850
    CLARK的薪水是2450
    SCOTT的薪水是3000
    KING的薪水是5000
    TURNER的薪水是1500
    ADAMS的薪水是1100
    JAMES的薪水是950
    FORD的薪水是3000
    MILLER的薪水是1300
     
    PL/SQL procedure successfully completed
     
    SQL> --光标练习:给员工涨工资  总裁1000 经理800 其它400
    SQL> --先查询没涨之前的
    SQL> select * from emp;
     
    EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO
    ----- ---------- --------- ----- ----------- --------- --------- ------
     7369 SMITH      CLERK      7902 1980/12/17     800.00               20
     7499 ALLEN      SALESMAN   7698 1981/2/20     1600.00    300.00     30
     7521 WARD       SALESMAN   7698 1981/2/22     1250.00    500.00     30
     7566 JONES      MANAGER    7839 1981/4/2      2975.00               20
     7654 MARTIN     SALESMAN   7698 1981/9/28     1250.00   1400.00     30
     7698 BLAKE      MANAGER    7839 1981/5/1      2850.00               30
     7782 CLARK      MANAGER    7839 1981/6/9      2450.00               10
     7788 SCOTT      ANALYST    7566 1987/4/19     3000.00               20
     7839 KING       PRESIDENT       1981/11/17    5000.00               10
     7844 TURNER     SALESMAN   7698 1981/9/8      1500.00      0.00     30
     7876 ADAMS      CLERK      7788 1987/5/23     1100.00               20
     7900 JAMES      CLERK      7698 1981/12/3      950.00               30
     7902 FORD       ANALYST    7566 1981/12/3     3000.00               20
     7934 MILLER     CLERK      7782 1982/1/23     1300.00               10
     
    14 rows selected
     
    SQL> --运行PLSQL语句
    SQL> 
    SQL> set serveroutput on
    SQL> declare
      2    --光标代表员工
      3    cursor cemp is select empno,job from emp;
      4    pempno emp.empno%type;
      5    pjob   emp.job%type;
      6  begin
      7    open cemp;
      8    loop
      9      fetch cemp into pempno,pjob;
     10      exit when cemp%notfound;
     11  
     12      --推断
     13      if pjob = 'PRESIDENT' then update emp set sal=sal+1000 where empno=pempno;	--总裁涨1000
     14        elsif pjob = 'MANAGER' then update emp set sal=sal+800 where empno=pempno; --经理涨800
     15        else update emp set sal=sal+400 where empno=pempno;	--其它涨400
     16      end if;
     17    end loop;
     18    close cemp;
     19  
     20    --提交: 隔离级别
     21    commit;
     22  
     23    dbms_output.put_line('完毕');
     24  end;
     25  /
     
    完毕
     
    PL/SQL procedure successfully completed
     
    SQL> --查询运行PLSQL语句后的薪水
    SQL> select * from emp;
     
    EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO
    ----- ---------- --------- ----- ----------- --------- --------- ------
     7369 SMITH      CLERK      7902 1980/12/17    1200.00               20
     7499 ALLEN      SALESMAN   7698 1981/2/20     2000.00    300.00     30
     7521 WARD       SALESMAN   7698 1981/2/22     1650.00    500.00     30
     7566 JONES      MANAGER    7839 1981/4/2      3775.00               20
     7654 MARTIN     SALESMAN   7698 1981/9/28     1650.00   1400.00     30
     7698 BLAKE      MANAGER    7839 1981/5/1      3650.00               30
     7782 CLARK      MANAGER    7839 1981/6/9      3250.00               10
     7788 SCOTT      ANALYST    7566 1987/4/19     3400.00               20
     7839 KING       PRESIDENT       1981/11/17    6000.00               10
     7844 TURNER     SALESMAN   7698 1981/9/8      1900.00      0.00     30
     7876 ADAMS      CLERK      7788 1987/5/23     1500.00               20
     7900 JAMES      CLERK      7698 1981/12/3     1350.00               30
     7902 FORD       ANALYST    7566 1981/12/3     3400.00               20
     7934 MILLER     CLERK      7782 1982/1/23     1700.00               10
     
    14 rows selected
     
    SQL> --对照涨之前,能够看出涨工资成功
    SQL> 
    SQL> --带參数的光标:查询某个部门的员工姓名
    SQL> set serveroutput on
    SQL> declare
      2    --定义一个带參数的光标
      3    cursor cemp(pdno number) is  select ename from emp where deptno=pdno;
      4    pename emp.ename%type;
      5  begin
      6    open cemp(20);	--打开光标。并传递參数
      7    loop
      8      fetch cemp into pename;
      9      exit when cemp%notfound;
     10  
     11      dbms_output.put_line(pename);
     12  
     13  
     14    end loop;
     15    close cemp;
     16  end;
     17  /
     
    SMITH
    JONES
    SCOTT
    ADAMS
    FORD
     
    PL/SQL procedure successfully completed
     
    SQL> 
    SQL> --举例 Zero_Divide   ( 被零除)
    SQL> set serveroutput on
    SQL> declare
      2    pnum number;
      3  begin
      4  
      5    pnum := 1/0;
      6  
      7  exception
      8    when Zero_Divide then dbms_output.put_line('1: 0不能做被除数');
      9                          dbms_output.put_line('2: 0不能做被除数');
     10    when Value_error then dbms_output.put_line('算术错');
     11    when others then dbms_output.put_line('其它例外');
     12  end;
     13  /
     
    1: 0不能做被除数
    2: 0不能做被除数
     
    PL/SQL procedure successfully completed
     
    SQL> 
    SQL> --自己定义例外: 查询50号部门的员工姓名
    SQL> set serveroutput on
    SQL> declare
      2    cursor cemp is select ename from emp where deptno=50;
      3    pename emp.ename%type;
      4  
      5    --自己定义例外
      6    no_emp_found exception;
      7  begin
      8    open cemp;
      9    --取一个员工
     10    fetch cemp into pename;
     11    if cemp%notfound then
     12      raise no_emp_found;
     13    end if;
     14  
     15    close cemp;
     16  
     17  exception
     18    when no_emp_found then dbms_output.put_line('没有找到员工');
     19    when others then dbms_output.put_line('其它例外');
     20  
     21  end;
     22  /
     
    没有找到员工
     
    PL/SQL procedure successfully completed
     
    SQL> spool off
    Stopped spooling to c:PLSQL.txt


    3.样例

    /*
    实例1:统计每年入职的员工个数。
    
    用到的SQL:
    select to_char(hiredate,'yyyy') from emp;
    */
    set serveroutput on
    declare
      cursor cemp is select to_char(hiredate,'yyyy') from emp;
      phiredate varchar2(4);
      
      --计数器
      count80 number := 0;
      count81 number := 0;
      count82 number := 0;
      count87 number := 0;
    begin
      open cemp;
      loop
        --取一个员工
        fetch cemp into phiredate;
        exit when cemp%notfound;
        
        --推断
        if phiredate = '1980' then count80:=count80+1;
          elsif phiredate = '1981' then count81:=count81+1;
          elsif phiredate = '1982' then count82:=count82+1;
          else count87 := count87+1;
        end if;      
    
      end loop;
      close cemp;
      
      --输出
      dbms_output.put_line('total:'||(count80+count81+count82+count87));
      dbms_output.put_line('1980:'|| count80);
      dbms_output.put_line('1981:'|| count81);
      dbms_output.put_line('1982:'|| count82);
      dbms_output.put_line('1987:'|| count87);
    end;
    /
    ------------------------------------------------------------------
    
    /*
    实例2:为员工长工资。从最低工资调起每人长10%,但工资总额不能超过5万元,
    请计算长工资的人数和长工资后的工资总额。并输出输出长工资人数及工资总额。
    
    可能的SQL:
    员工:  select empno,sal from emp order by sal;
    长工资后的工资总额:1. 对sal进行累加: 新的工资总额=旧的工资 + sal*0.1;
                    2. sum(sal): 查询数据库
    练习: 工资不能超过5w
    */
    set serveroutput on
    declare
      --员工
      cursor cemp is select empno,sal from emp order by sal;
      pempno emp.empno%type;
      psal   emp.sal%type;
      
      --长工资的人数
      countEmp number := 0;
      --工资总额
      salTotal number;
    begin
    
       --涨前工资总额
      select sum(sal) into salTotal from emp;
    
      open cemp;
      loop
        --工资总额>5w
        exit when salTotal > 50000;
        --取一个员工
        fetch cemp into pempno,psal;
        exit when cemp%notfound;
        
        --涨工资
        update emp set sal=sal*1.1 where empno=pempno;
        --人数
        countEmp := countEmp +1;
        --工资总额
        salTotal := salTotal + psal * 0.1;
      end loop;
      close cemp;
      
      commit;
    
      --输出
      dbms_output.put_line('长工资的人数:'|| countEmp);
      dbms_output.put_line('工资总额:'|| salTotal);
    
    end;
    /
    ------------------------------------------------------------------
    /*
    实例3:用PL/SQL语言编写一程序,实现按部门分段(6000以上、(6000,3000)、3000元以下)
    统计各工资段的职工人数、以及各部门的工资总额(工资总额中不包含奖金)
    
    SQL语句:
    部门:  select deptno from dept;
    员工的工资: select sal from emp where deptno=???
    工资总额:  select sum(sal) from emp where deptno=??

    ? */ set serveroutput on declare --部门 cursor cdept is select deptno from dept; pdno dept.deptno%type; --部门中的员工 cursor cemp(dno number) is select sal from emp where deptno=dno; psal emp.sal%type; --各个段的人数 count1 number;count2 number;count3 number; --部门的工资总额 salTotal number; begin open cdept; loop --取部门 fetch cdept into pdno; exit when cdept%notfound; --初始化 count1 :=0;count2:=0;count3:=0; select sum(sal) into salTotal from emp where deptno=pdno; --取部门中的员工 open cemp(pdno); loop fetch cemp into psal; exit when cemp%notfound; --推断 if psal<3000 then count1:=count1+1; elsif psal>=3000 and psal<6000 then count2:=count2+1; else count3:=count3+1; end if; end loop; close cemp; --保存当前部门 insert into msg1 values(pdno,count1,count2,count3,nvl(salTotal,0)); end loop; close cdept; commit; dbms_output.put_line('完毕'); end; /



  • 相关阅读:
    iptables
    vsftpd安装
    完整java开发中JDBC连接数据库代码和步骤
    java中使用队列:java.util.Queue
    程序中遇到重点问题
    在JSP页面中用select下拉列表来显示List列表的方式
    java.lang.String cannot be cast to [Ljava.lang.Object;
    java虚拟机的内存设置
    网络协议都有哪些
    使用java技术将Excel表格内容导入mysql数据库
  • 原文地址:https://www.cnblogs.com/mqxnongmin/p/10548065.html
Copyright © 2011-2022 走看看