PL/SQL块  declare  begin   --SQL语句   --直接写的SQL语句(DML/TCL)   --间接写execute immediate     --select 语句        必须带有into子句         select empno into eno from emp           where empno =7369;        只能查到一行**********        字段个数必须和变量的个数一致  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        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循环游标 (常用的一种游标)  --定义游标 --定义游标变量 --使用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; 执行存储过程的方法      execute p_jd;     (SQL*PLUS中SQL>)      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;       --调用方法     PL/SQL块调用       declare       aa number;      begin        aa := f_getavgsal(10)  ;        dbms_output.put_line(to_char(aa));      end;      SQL语句来调用(DML)        select f_getavgsal(10) from dual;       select deptno,f_getavgsal(deptno) from dept;            create or replace function f1       return number       as         update emp set comm = 1000           where job='CLERK';         return sql%rowcount;       end;      --select语句是无法调用它的,因为其中含有修改语句
01-30 20:01