zoukankan      html  css  js  c++  java
  • PLSql语句学习(三)

    PL/SQL块
      declare
      begin
       --SQL语句
       --直接写的SQL语句(DML/TCL)
       --间接写execute immediate <DDL/DCL命令字符串>
       --select 语句
            <1>必须带有into子句
             select empno into eno from emp
               where empno =7369;
            <2>只能查到一行**********
            <3>字段个数必须和变量的个数一致
      exception
        --异常
        when <异常名字> then --特定异常
            <处理语句>
        when others then  --所有异常都可捕获
            <处理语句>  
      end;
    <例子>
       编写程序 向DEPT表中插入一条记录,
       从键盘输入数据,如果
          数据类型输入错误要有提示
          无法插入记录 也要有提示
          只能输入正数,如果有负数提示
       declare
        n number;
        no dept.deptno%type;
        nm dept.dname%type;
        lc dept.loc%type;
        exp exception;   --异常的变量
        exp1 exception;
        num number:=0;  --计数器
        pragma exception_init(exp,-1); --预定义语句
             --(-1错误和异常变量关联)
        pragma exception_init(exp1,-1476);
        e1 exception; --自定义异常变量
       begin
        --输入值
         no := '&编号';
         num := num + 1;
         if no < 0 then
            raise e1;    --自定义异常的引发
         end if;
         nm := '&名称';
         num := num +1;
         lc := '&地址'; 
         num := num +1;
         n := 10 /0;    
         insert into dept values (no,nm,lc);
         num := num +1;
         commit;
       exception
         --自定义异常
         when e1 then
            dbms_output.put_line('编号不能为负数');
         --数据类型不对
         when value_error then
            if num =0 then 
             dbms_output.put_line('编号数据类型不对');
            elsif num = 1 then
             dbms_output.put_line('名称数据类型不对');
            elsif num =2 then
             dbms_output.put_line('地址数据类型不对');
            end if;
            rollback;
         --主键冲突
         when exp then
             --sqlcode全局变量 异常错误号
             --sqlerrm全局变量 异常的文字信息 
             --dbms_output.put_line('异常的编号:'||sqlcode);
             --dbms_output.put_line('异常的内容:'||sqlerrm);
             --dbms_output.put_line('编号已存在') ;
             rollback;
         --非预定义异常(关联错误号)
         when exp1 then
             --dbms_output.put_line('0做了除数') ;
             raise_application_error(-20001,'0做了除数'); --引起一个自定义的错误
             --预先保留-20001 到 -29999编号
             rollback;
         --其他的异常
         when others then
             dbms_output.put_line('异常的编号:'||sqlcode);
             dbms_output.put_line('异常的内容:'||sqlerrm);
            -- dbms_output.put_line('出现错误');
             rollback;
       end; 
    --    insert into dept values (40,'asdf','asdf');
    <简单的做法>
      --存放异常的
       create table save_exp(
          bh number,
          wz varchar2(1000)
       );
       declare
        no dept.deptno%type;
        nm dept.dname%type;
        lc dept.loc%type;
        errno number;
        errtext varchar2(1000);
       begin
         no := '&编号';
         nm := '&名称';
         lc := '&地址';
     
         insert into dept values (no,nm,lc);
         commit;
       exception
        when others then
          rollback;
          errno := sqlcode;
          errtext := sqlerrm;      
          insert into save_exp values (errno,errtext);
          commit;
       end;
    <游标>  内存中的一块区域,存放的是select 的结果
      
       1。 隐式游标
         单条sql语句所产生的结果集合
           用关键字SQL表示隐式游标
            4个属性 %rowcount  影响的记录的行数  整数
                    %found     影响到了记录 true
                    %notfound  没有影响到记录 true
                    %isopen    是否打开  布尔值 永远是false
             多条sql语句 隐式游标SQL永远指的是最后一条sql语句的结果
             主要使用在update 和 delete语句上     
       2。 显式游标
          select语句上 使用显式游标
          明确能访问结果集
             for循环游标
             参数游标
               解决多行记录的查询问题
             fetch游标
    显示游标
       需要明确定义
       (1)FOR循环游标 (常用的一种游标)
     --<1>定义游标
     --<2>定义游标变量
     --<3>使用for循环来使用这个游标
      --前向游标 只能往一个方向走
      --效率很高
          declare
            --类型定义
            cursor cc is select empno,ename,job,sal
             from emp where job = 'MANAGER';
            --定义一个游标变量
            ccrec cc%rowtype;

          begin
             --for循环
             for ccrec in cc loop
                dbms_output.put_line(ccrec.empno||'-'||ccrec.ename||'-'||ccrec.job||'-'||ccrec.sal);
             end loop;
          
          end;
       (2) fetch游标
         --使用的时候 必须要明确的打开和关闭
          declare
            --类型定义
            cursor cc is select empno,ename,job,sal
             from emp where job = 'MANAGER';
            --定义一个游标变量
            ccrec cc%rowtype;

          begin
            --打开游标
             open cc;
            --loop循环
             loop
                --提取一行数据到ccrec中
                fetch cc into ccrec;        
                --判断是否提取到值,没取到值就退出
                --取到值cc%notfound 是false
                --取不到值cc%notfound 是true
                exit when cc%notfound;
                dbms_output.put_line(ccrec.empno||'-'||ccrec.ename||'-'||ccrec.job||'-'||ccrec.sal);           
             end loop;
            --关闭
             close cc; 
          
          end;
      游标的属性4种
           %notfound  fetch是否提到数据 没有true 提到false
           %found      fetch是否提到数据 有true 没提到false
           %rowcount  已经取出的记录的条数
           %isopen    布尔值 游标是否打开
     declare
            --类型定义
            cursor cc is select empno,ename,job,sal
             from emp where job = 'MANAGER';
            --定义一个游标变量
            ccrec cc%rowtype;
      
          begin
            --打开游标
             open cc;
            --loop循环
             loop
                --提取一行数据到ccrec中
                fetch cc into ccrec;        
                --判断是否提取到值,没取到值就退出
                --取到值cc%notfound 是false
                --取不到值cc%notfound 是true
                exit when (cc%notfound or cc%rowcount =3);
                dbms_output.put_line(cc%rowcount||'-'||ccrec.empno||'-'||ccrec.ename||'-'||ccrec.job||'-'||ccrec.sal);           
             end loop;
            --关闭
             close cc; 
          
          end;
    <例子>
      declare
           cursor cc is select dept.dname,
            emp.ename,emp.sal from
             dept,emp where dept.deptno = emp.deptno;
           ccrec cc%rowtype;
      begin
          for ccrec in cc loop
         
           dbms_output.put_line(ccrec.dname||'-'||ccrec.ename||'-'||ccrec.sal);
          end loop;
      
      end; 
       (3)参数游标
     按部门编号的顺序输出部门经理的名字
         declare
           --部门
           cursor c1 is select deptno from dept;
           --参数游标c2,定义参数的时候
           --只能指定类型,不能指定长度 
           --参数只能出现在select语句=号的右侧
           cursor c2(no number,pjob varchar2) is select emp.* from emp
             where deptno = no and job=pjob;
        /*
           no = 10  pjob = 'MANAGER'
              select * from emp where deptno = 10 and job = 'MANAGER';  
         */
           c1rec c1%rowtype;
           c2rec c2%rowtype;
           --定义变量的时候要指定长度
           v_job varchar2(20);
         begin
           --部门
            for c1rec in c1 loop
              --参数在游标中使用
              for c2rec in c2(c1rec.deptno,'MANAGER') loop
                dbms_output.put_line(c1rec.deptno||'-'||c2rec.ename);
              end loop;
            end loop;
         end;
    <综合例子>
      求购买的商品包括了顾客"Dennis"所购买商品的顾客(姓名);**************
       思路:
          Dennis (A,B)
          别的顾客 (A,B,C) (A,C) (B,C)  C
      declare
       --Dennis所购买的商品
       cursor cdennis is select productid
             from purcase where customerid=(
               select customerid from
               customer where name = 'Dennis');
       --除Dennis以外的每个顾客
       cursor ccust is select customerid
            from customer where name <> 'Dennis';
       --每个顾客购买的商品
       cursor cprod(id varchar2) is
         select productid from purcase
              where customerid = id;
       j number ;
       i number;
       c1rec cdennis%rowtype;
       c2rec ccust%rowtype;
       c3rec cprod%rowtype;
       cname varchar2(10);
      begin
        --顾客循环
        for c2rec in ccust loop
         i:=0;
         j:=0;
         for c1rec in cdennis loop
            i := i + 1;
           
          --每个顾客买的东西
           for c3rec in cprod(c2rec.customerid) loop
               if (c3rec.productid = c1rec.productid) then
                   j := j + 1;
               end if;
            end loop;  
         
         end loop;
                           
           if (i=j) then
            select name into cname from
               customer where customerid = c2rec.customerid;
            DBMS_output.put_line(cname);       
           end if;
        end loop;
      end;
      (4)引用游标/动态游标
            select语句是动态的
         declare
           --定义一个类型(ref cursor)弱类型   
           type cur is ref cursor;
             --强类型(返回的结果集有要求)
           type cur1 is ref cursor return emp%rowtype;
           --定义一个ref cursor类型的变量  
           cura cur;
           --
           c1rec emp%rowtype;
           c2rec dept%rowtype;
         begin
      DBMS_output.put_line('输出员工')   ;      
           open cura for select * from emp;
           loop
             fetch cura into c1rec;  
             exit when cura%notfound;
             DBMS_output.put_line(c1rec.ename)   ;
           end loop ;
      DBMS_output.put_line('输出部门')   ;
           open cura for select * from dept;
           loop
             fetch cura into c2rec;  
             exit when cura%notfound;
             DBMS_output.put_line(c2rec.dname)   ;
           end loop; 
           close cura;
        end;
    >>>>>存储过程和函数
      没有名字的PL/SQL块(匿名)
      有名字的PL/SQL块(子程序-存储过程和函数)
    存储过程
          create or replace procedure p1
          as
          begin
          exception
          end;
    <最简单的存储过程>
           create or replace procedure p_jd
           as
             hello varchar2(20); 
           begin
            select 'Hello World' into hello from dual;
            dbms_output.put_line(hello);
           end;
     执行存储过程的方法
          <1> execute p_jd;     (SQL*PLUS中SQL>)
          <2> begin
               p_jd;
              end; 
     带参数的存储过程
       --输入参数in
       --不写in的参数都是输入参数
       --根据部门编号查员工姓名
        create or replace procedure p_getemp(no  number)
        as
          cursor c1 is select * from emp
           where deptno = no;
          c1rec c1%rowtype;
        begin
      --       no := 20; 输入参数是不能赋值的
           for c1rec in c1 loop
            dbms_output.put_line(c1rec.ename);
           end loop;
        end;    
       --输出参数out
       --根据部门编号查出部门的平均工资,返回平均工资的值
       -- in 输入 (在procedure中是不能赋值的)
       --  out 输出 (在procedure中是能赋值的)
    -- 定义参数是不能指定长度的
     --定义变量是必须指定长度的
        create or replace procedure p_getavgsal(no  number,avgsal out number)
        -- no   输入参数
        -- avgsal  输出参数
        as
         aa varchar2(10); --变量
        begin
           select avg(sal) into avgsal
           from emp where deptno = no; 
        end;    
        调用它只能使用PL/SQL块
            declare
             av number;
            begin         
              p_getavgsal(10,av);
              dbms_output.put_line('平均工资:'||round(av,2));
            end;       
       --一个参数同时可以输入,也可以输出
       --输入输出参数
        create or replace procedure
        p_getavgsal(n in out number)
        as
        begin
           select avg(sal) into n
           from emp where deptno = n; 
        end;
       
       declare
             av number;
            begin         
              av  := 10;
              p_getavgsal(av);
              dbms_output.put_line('平均工资:'||round(av,2));
            end;       
      --带多个参数的存储过程
         create or replace procedure
          p_getM(no number,pjob varchar2) as
           --参数游标c2,定义参数的时候
           --只能指定类型,不能指定长度 
           --参数只能出现在select语句=号的右侧
           cursor c2(no1 number,pjob1 varchar2) is select * from emp
             where deptno = no1 and job=pjob1;
           c2rec c2%rowtype;
           --定义变量的时候要指定长度
           v_job varchar2(20);
         begin
              --参数在游标中使用
              for c2rec in c2(no,pjob) loop
                dbms_output.put_line(c2rec.deptno||'-'||c2rec.ename);
              end loop;
         end;
      
        调用方法:execute p_getm(10,'MANAGER'); --按位置
       -- no = 10 , pjob = 'MANAGER'
              
          execute p_getm(pjob => 'MANAGER',no => 10);
       --按参数的名字 来传值
      函数:
        必须要有返回值
        只能返回一个值
      
       --根据部门编号查出部门的平均工资,返回平均工资的值(利用函数)
        create or replace function
        f_getavgsal(no number)
        return number
        as
          avgsal number(7,2);
        begin
           select avg(sal) into avgsal
           from emp where deptno = no;
           --返回值
           return avgsal;  
        end;  
     
    --带输出参数
     --每个部门的平均工资和工资总额
     --一个函数返回2个值
    create or replace function
        f_getavgsal(no number,sumsal out number)
        return number
        as
          avgsal number(7,2);
        begin
           --平均工资
           select avg(sal) into avgsal
           from emp where deptno = no;
           --工资总额
           select sum(sal) into sumsal
           from emp where deptno = no;
           --返回值
           return avgsal;  
        end;    
      --调用方法
         <1>PL/SQL块调用
          declare
           aa number;
          begin
            aa := f_getavgsal(10)  ;
            dbms_output.put_line(to_char(aa));
          end; 
        <2> SQL语句来调用(DML)
           select f_getavgsal(10) from dual;
           select deptno,f_getavgsal(deptno) from dept;
        <3>
           create or replace function f1
           return number
           as
             update emp set comm = 1000
              where job='CLERK';
             return sql%rowcount;
           end;
          --select语句是无法调用它的,因为其中含有修改语句
  • 相关阅读:
    动态生成 Excel 文件供浏览器下载的注意事项
    JavaEE 中无用技术之 JNDI
    CSDN 泄露用户密码给我们什么启示
    刚发布新的 web 单点登录系统,欢迎下载试用,欢迎提建议
    jQuery jqgrid 对含特殊字符 json 数据的 Java 处理方法
    一个 SQL 同时验证帐号是否存在、密码是否正确
    PostgreSQL 数据库在 Windows Server 2008 上安装注意事项
    快速点评 Spring Struts Hibernate
    Apache NIO 框架 Mina 使用中出现 too many open files 问题的解决办法
    解决 jQuery 版本升级过程中出现 toLowerCase 错误 更改 doctype
  • 原文地址:https://www.cnblogs.com/HondaHsu/p/804300.html
Copyright © 2011-2022 走看看