zoukankan      html  css  js  c++  java
  • Oracle-4

    初学者可以从查询到现在的pl/sql的内容都可以在我这里的笔记中找到,希望能帮到大家,视频资源在 资源,

    我自己的全套笔记在  笔记

    在pl/sql中可以继续使用的sql关键字有:update delete insert select--into commit  rollback savepoint   ,在这里需要注意的是查询跟以前有些不一样了

    plsql由三个块组成:声明部分,执行部分,异常处理部分

      declare:在此声明pl/sql用到的变量,类型及游标,以及局部的存储过程的和函数

      begin:执行部分:过程及sql语句,即程序的主要部分

      exception:执行异常部分,错误处理

      end

        其中执行部分是必要的

    pl/sql之helloworld

        set SERVEROUTPUT ON   --首先必须执行此语句,否则没有输出
        begin
        dbms_output.put_line('hello world');
        end;  --下图前三个均是没有执行set serveroutput on 语句的执行结果,在执行完此语句才能有输出

        其中只有begin部分,和结束end,因为此语句不需要变量声明就省去了declare部分,和exception错误部分

          

     变量常量等的命名规则,下列标红的就是建议使用的命名的开头

          

       实例:用pl/sql查询出tno为t001的老师的名字并输出

          下面的select 语句是把查询结果放到了变量v_name中然后输出

          declare
            v_name TEACHER.TNAME%TYPE; --这里是动态的获取teacher表中tname字段的类型

             v_tno varchar2(10);
          begin
            --普通查询语句 :select * from teacher where tno ='t001';
            select tno,tname into v_tno,v_name from teacher where tno ='t001';
            SYS.DBMS_OUTPUT.PUT_LINE(v_name||','||v_tno);
          end;

      记录类型:是把逻辑相关的数据作为一个单元存储起来,其作用是存放互不相同但逻辑相关的信息,类似java中一个类的概念一样

            注意不能将select语句中的列赋值给布尔变量

          declare

              --在为一个变量赋值的时候的格式   :     v_tno number(10) :=10;   自这里  “:=”是赋值,判断为=
            --type 自定义名1 is record
              type teacher_mas is record (
                  v_name TEACHER.TNAME%TYPE, --逗号
                  v_tno varchar2(10)  --无标点符号
              );
              -- 定义一个记录类型的成员变量
              --自定义2  自定义名1   在这就相当于创建了一个对象
              v_teacher_mas teacher_mas;

              --如果字段特别多的话  我们可以使用:v_teacher_mas  teacher%rowtype;   表示与teacher表中的所有的类型都一直 ,下面就直接可以查询 *  into v_teacher_mas 了
          begin
            --普通查询语句 :select * from teacher where tno ='t001';
            select tno,tname into v_teacher_mas from teacher where tno ='t001';
            SYS.DBMS_OUTPUT.PUT_LINE(v_teacher_mas.v_name||','||v_teacher_mas.v_tno);
          end;

      流程控制语句:

          if 语句结构:   if  《条件表达式》 then ---- end if;  相当于 java中   if() {}

                  if  《条件表达式》 then -- else-- end if; 相当于java中的  if(){} else {}

                  if  《条件表达式》 then -- els if《条件表达式》-- endif;这里是elsif 不是elseif  相当于java中的多重判断了就 :if(){} elseif (){} eles{}

            实例:--查询sno为s001的学生的c001课程的成绩,如果大于60输出及格 小于60输出不及格 其他输出一般

                每次的if或者elsif必须跟一个分隔符 用end if作为结束标志,当然同一个if后可以加and
            declare
               v_score SC.SCORE%type;
            begin
              select score into v_score from sc where sc.sno='s001' and CNO='c001';
              if v_score<60  then SYS.DBMS_OUTPUT.PUT_LINE('不及格');
                  elsif v_score >=60 then SYS.DBMS_OUTPUT.PUT_LINE('及格');
                  else SYS.DBMS_OUTPUT.PUT_LINE('一般');
                  end if;
            end;

         case语句结构:case 值 

                  when  表达式   then

                  when  表达式   then

                  else

                end;

         由于case比较恶心,sno为s001的学生的c001课程的成绩为78.9,看下查询sql,在这里case跟Java、中的switch一样

            case 一个值,when 后  只能跟常量,并且 then后不能赋值,输出等,只可以返回结果

          declare
             v_score SC.SCORE%type;
             v_mas varchar2(30);
          begin
            select score into v_score from sc where sc.sno='s001' and CNO='c001';
            v_mas :=
              case v_score when 78.9 then '及格'
                               when 60 then '不及格'
                                else '一般'
                end;

              SYS.DBMS_OUTPUT.PUT_LINE(v_mas);
           end;

       循环结构: 实例  输出1--100 用循环结构

            1.  loop...exit...where ....end loop   

               
              declare
                  v_min number(3):=1;
              begin
                  loop
                      SYS.DBMS_OUTPUT.PUT_LINE(v_min);
                  exit when v_min >= 100;
                      v_min := v_min +1;
                  end loop;
              end;     

            2.  while<布尔表达式> loop   要执行的语句 end loop;

              declare
                  v_i number(3):=1;
              begin
                  while v_i <=100 loop
                      SYS.DBMS_OUTPUT.PUT_LINE(v_i);
                      v_i := v_i +1;
                  end loop;
              end;

            3. for 循环计数器 in【reverse】 上限 .. 下限 loop   要执行的语句  end loop;不要忘记上限于下限中间有两个点

                每循环一次变量自动+1,使用关键字reverse自动-1 ,跟在in reverse 后面的数字必须是从小到大的顺序,而且必须是整数,不能是变量或者表达式,可以使用exit 退出循环

                begin
                  for c in 1..100 loop
                     SYS.DBMS_OUTPUT.PUT_LINE(c);
                   end loop;
                end;

        标号与goto:无条件的跳到指定的标号去的意思

            实例 :打印1到100 ,当打印到50的时候,打印结束循环,然后结束整个循环

                declare
                      v_i number(3):=1;
                begin
                    while v_i<=100 loop
                          if v_i=50
                             then goto label;
                           end if;
                           SYS.DBMS_OUTPUT.PUT_LINE(v_i);
                            v_i := v_i+1;
                    end loop;
                   <<label>>
                      SYS.DBMS_OUTPUT.PUT_LINE('结束循环');
                end;

        游标的使用:类似java中的迭代器Iterator,游标是一个指向上下文的句柄或指针,通过游标,可以处理多行记录

              

         1. 显示游标处理

            显示游标处理四步骤

              1. 定义游标:cursor --is -- 在指定数据类型时,不能使用长度约束

              2. 打开游标:open --  : 程序不能用open语句重复打开一个游标

              3. 提取游标:fetch--into--

              4. 关闭游标: close--

           游标实例:打印出80号部门的所有员工的信息
               declare
                    --记录类型
                    type emp_mas is record(
                        v_empid employees.employee_id%type,
                        v_name employees.last_name%type,
                        v_sal employees.salary%type
                      );
                     --记录类型对象
                      emp_mas_record emp_mas;
                      --定义游标
                      cursor emp_ens_mas is select employee_id,last_name,salary from employees where department_id=80;
                begin
                    --打开游标
                    open emp_ens_mas;
                    --提取游标
                    fetch emp_ens_mas into emp_mas_record;
                    --emp_ens_mas%found  相当于java中的hashNext
                      while emp_ens_mas%found loop
                          SYS.DBMS_OUTPUT.PUT_LINE(emp_mas_record.v_empid||','||emp_mas_record.v_name||','||emp_mas_record.v_sal);
                          fetch emp_ens_mas into emp_mas_record;
                      end loop;
                      --关闭游标
                      close emp_ens_mas;
                  end;

          2.  游标的for循环:pl/sql提供了游标for循环,自动执行游标的open,fetch,close语句和循环语句的功能,当进入循环时,游标for循环语句自动打开游标,并提取

                    第一行游标数据,当程序处理完当前所提取的数据而进入下一次循环时,游标for循环语句会东子提取下一行数据供程序处理,当提取完结果

                    集中的所有数据行后结束循环,并自动游标

              格式:for  变量   in  游标 loop   -----end loop;

            与上题一样,打印出80号部门的所有员工的信息

                declare
                  --定义游标
                  cursor emp_ens_mas is select employee_id,last_name,salary from employees where department_id=80;
                begin
                    for c in emp_ens_mas loop
                           SYS.DBMS_OUTPUT.PUT_LINE(c.employee_id||','||c.last_name||','||c.salary);
                    end loop;
                end;

          3. 异常的捕获与处理

            1. 预定义异常,就是已经系统定义好的一些异常,这些异常由系统自动抛出,如下

                

                  

                declare
                    v_i number(30);
                begin
                    select salary into v_i from employees where employee_id >=100;
                    SYS.DBMS_OUTPUT.PUT_LINE(v_i);
                end;

                    由于employee_id >= 100 的员工的工资返回的结果不止一个  ,所以这里就会出现 返回值太多的一场 

                    

                此时就可以在exception中捕获此异常并进行处理,如果不处理的话,系统报错并且程序整体终止

                  declare
                      v_i number(30);
                  begin
                      select salary into v_i from employees where employee_id >=100;
                      SYS.DBMS_OUTPUT.PUT_LINE(v_i);
                  exception
                       when Too_many_rows then SYS.DBMS_OUTPUT.PUT_LINE('返回值太多了!!');

                     when others then SYS.DBMS_OUTPUT.PUT_LINE('其他错误!!');
                  end;

                  上面捕获的是系统预定义异常Too_many_rows ,如果产生其他不知道的异常可以使用others 进行捕获并处理

            2. 非预定义异常的处理

                对于非预定异常的处理,首先必须对非定义的oracle错误进行定义,步骤

                  1. 在pl/sql块的定义部分定义异常情况:<异常情况>exception;

                  2. 将其定义好的异常情况,与标准的oracle错误连接起来,使用 pragma exception_init 语句:pragma exception_init(<异常情况>,<异常代码>);

                  3. 在pl/sql块的异常情况处理部分对异常情况做出相应的处理

              我们来删除employee_id = 100的用户

                declare
                begin
                   delete  from employees where employee_id =100;
                end;

              这时候由于100号员工有子记录,employee_id 等于 本表的manager_id,所以删除不了

              

              上面爆出来的错误代码 2292 没有在oracle中的预定义异常,我们这时候就只能自己定义错误名与此错误号相关联

                declare
                      my_exception exception;
                      pragma exception_init(my_exception,-2292);
                begin
                    delete  from employees where employee_id =100;
                exception
                   when my_exception then SYS.DBMS_OUTPUT.PUT_LINE('违反约束  非预定义异常!!');
                end;

                

           3. 用户自定义的异常处理

              用户自定义异常是通过显示使用 raise 语句来触发的,当引发一个异常错误的时候,控制就转向到exception块异常错误部分

                对于这类异常情况的处理步骤如下

                  1. 在pl/sql块的定义部分定义异常情况  <异常情况>exception;

                  2. raise <异常情况>

                  3. 在pl/sql块的异常情况处理部分对异常情况做出相应的处理。

              实例:查询employee_id 为100 号员工的工资,如果工资>1w则抛出异常“工资高”

                declare
                      my_exception exception;
                      v_i number(5) ;
                begin
                    select salary into v_i from employees where employee_id =100;
                       if v_i>10000 then
                            raise my_exception;  --出发自定义异常
                      end if;
                 exception
                   when my_exception then SYS.DBMS_OUTPUT.PUT_LINE('工资高!!');
                end;

                

    存储函数与存储过程

        Oracle 提供可以把pl/sql程序存储在数据库中,并可以在任何地方来运行他,这样就叫存储过程或函数

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

      创建一个函数:  创建函数时如果重名直接覆盖创建

          1. 建立内嵌函数 

              语法:  create or replace function 函数名 (id number ,name varchar2)

                  return  number

                  is   --需要使用的变量游标等可以在这里定义

                  begin --函数体

                  exception  --异常接受处理

                  end;

              实例,写一个可以返回helloworld 的函数(无参函数)

                create or replace function get_helloWorld
                return varchar2
                is
                begin
                    return 'Hello World';
                end;

                函数创建完成调用此函数:1. select GET_HELLOWORLD from dual;  

                            2. begin
                                SYS.DBMS_OUTPUT.PUT_LINE(GET_HELLOWORLD);
                                end;

                 (有参函数):create or replace function get_helloWorld(name varchar2)   --不需要指定长度
                        return varchar2
                        is
                        begin
                               return 'Hello World ' || name;
                        end;

                  调用:select GET_HELLOWORLD('纯菜鸟') from dual;  

           2. 关于out函数:pl/sql程序可以通过out型的参数实现有多个返回值

              in参数标记表示传递给函数的值在该函数执行中不改变;out标记表示一个值在函数中进行计算并通过该参数传递给调用语句,in out 标记标识传递给函数的值可以变化

                并传递给调用语句。若省去标记,则参数隐含为in 。return 包含返回结果的数据类型

                实例:定义一个函数,获取给定部门的工资总和 和 该部门的员工总数(定义为out类型的参数)

                    要求:部门号定义为参数,工资总额定义为返回值

         创建函数:  create or replace function get_salary(empid number,empNum out number)
                return number
                is
                      v_sal number(6) :=0;
                      cursor my_emp_cur is select salary from employees where department_id = empid;
                begin
                     empNum :=0;  --参数只能在函数体中赋值,如果不对请指正
                      for c in my_emp_cur loop
                           v_sal := c.salary + v_sal; --工资
                           empNum := empNum+1;
                      end loop;
                      return v_sal;
                end;

         调用函数:declare
                  v_count_people_number number(3);--存储人数的变量
                  begin
                  SYS.DBMS_OUTPUT.PUT_LINE( get_salary(80,v_count_people_number));
                  SYS.DBMS_OUTPUT.PUT_LINE(v_count_people_number);
              end;  

             --从调用函数这就可以看到,在上面out函数中并没有显示返回人数,但是在调用的时候,Oracle会带回参数并存到自己定义的变量中,此时输出只会输出函数返回的结果,而输出待会的参数

        存储过程创建:获取给定部门的工资总和(out) ,要求:部门号和工资总额定义为参数

                create or replace procedure get_sal(empid number,sum_sal out number)
                is
                    cursor my_emp_cur is select salary from employees where department_id = empid;
                begin
                    sum_sal :=0;
                      for c in my_emp_cur loop
                          sum_sal := sum_sal+c.salary;
                      end loop;
                end;

            我们发现存储过程的语法格式与存储函数的语法格式只是相差  过程是 procedure 无return,,而函数是function  有return

          调用:declare
                  v_count_people_number number(7);
             begin
                   get_sal(80,v_count_people_number);
                    sys.dbms_output.put_line(v_count_people_number);
             end;

                

        触发器:类似过程和函数,都有声明,执行,和异常处理过程的pl/sql块,区别与存储过程,存储过程是由程序调用,而触发器是由事件触发调用,触发器不能接受参数,Oracle事件指的是对表或视图的增删改

              可以在增删改操作前或者操作后进行触发,可以对每个行或语句操作上进行触发。

            触发器的组成:

              1. 触发事件:增删改

              2. 触发时间:before  after

              3. 触发器本身 :

              4. 触发频率:语句级(statement)触发器  和   行级(row)触发器:例如更改一个表的工资,如果更改一个人的触发一次就是行级,如果整个表更改前或后触发就是语句级

          创建触发器的语法

              create [or replace ] trigger 名字 

              before | after

              insert | update | delete  [of column]

              on table

              [for each row]     --行级还是语句级的,写上的话就是行级的,不写就是语句级的

              where  ---

            在teacher 表上的 tname 上添加触发器:当更新update tname的时候 输出:tname被更改

                  create or replace trigger tea_tname_up
                  after     --事件之前被触发
                  update of tname on teacher   --作用在teacher 表上的tname列中,也可以直接作用在表上,去掉行就行 直接on table

                      --不写就是语句级的,写for each row 就是行级的
                  begin     --被触发后做的事情
                  SYS.DBMS_OUTPUT.PUT_LINE('tname被更改');
                  end;

              当更新:update teacher set tname ='纯菜鸟' where tid=1; 时

              

          :new  和  :old修饰符:比如更改表中的数据,用这两个就可以看到更新前和更新后的数据

            修改上面的触发器,使其tname更改后,输出更改前的和更改后的

              create or replace trigger tea_tname_up
              after
              update of tname on teacher
              for each row    --作用与每行,使用new 和old  必须加上这个
              begin
                 SYS.DBMS_OUTPUT.PUT_LINE('修改前的:'||:old.tname||'   修改后的:'||:new.tname);
              end;

              更改tname:update teacher set tname ='懒蛋' where tid=1;

                

        实例:当删除teacher 表中的数据的时候,吧删除的数据备份到 teacher_bak;

            teacher中的数据

                

            teacher_bak中的数据

                

            触发器创建:create or replace trigger teacher_two_bak
                  after
                  delete on teacher
                  for each row
                  begin
                      insert into teacher_bak values (:old.tid,:old.tname);
                  end;

            测试:delete from teacher where tid = 1;

           执行完后,teacher 与 teacher_bak 中的数据分别是

                ......


     

  • 相关阅读:
    python学习之——pip的安装与使用
    python学习之——django环境搭建
    python学习之——eclipse+pydev 环境搭建
    linux学习之——vim简明教程
    深度公式
    带宽、延时、吞吐率、PPS
    人脸应用:人脸检测、人脸对比、五官检测、眨眼检测、活体检测、疲劳检测
    非交互式人脸活体检测(002)
    活体检测记录(001)
    Learning Generalizable and Identity-Discriminative Representations for Face Anti-Spoofing
  • 原文地址:https://www.cnblogs.com/wzqjy/p/7810701.html
Copyright © 2011-2022 走看看