zoukankan      html  css  js  c++  java
  • pl/sql程序语言

    pl/sql程序基础知识:

      pl/sql(procedural language/sql)oracle在标准sql上面的扩展,不仅简单的sql语句,还具有一般语言的特性:变量,常量,流程控制和循环,错误处理机制.是一个功能完善强大的过程化语言.

      它的编程基本单位是块,复杂的功能都是多个块组成

        我们来看看它的实列代码:

    块结构:
            declear --定义部分,可选
            /*定义部分--变量,常量,游标,异常,复杂数据类型*/
            begin --执行部分
            /*pl/sql语句和SQL语句;*/
            exception --异常处理部分,风险程度.可选
            /*异常处理部分*/
            end;
            /    --和java对比

      pl/sql写的代码段实际上保存在数据库中的数据对象,根据功能不同分为过程,函数,触发器.这些代码端口,可以直接在java程序中直接调用

      它的目的:将程序逻辑变为数据库逻辑,降低程序端复杂度,让更好的进行模块化编程

      它的作用:作用:提高整个程序系统的性能,让模块化编程思想更简单实现,降低网络传输量.更安全

      当然pl/sql也有缺点:它的移植性不好

      


     

    存储过程:

      我们来来说说原理:

        执行特定的操作过程,有参数输入(in),有结果输出(out).,他们都在内部的传递过程要借助变量,把数据传递到执行部分,输出吧结果输出到调用部分

      它是怎么增加的呢??请看下面代码

    --=案例一
    create or replace procedure mypro is  --这里的命名不要和你的表名重合,ORA-04044: procedure, function, package, or type is not allowed here
    begin
    --执行部分
    insert into c##scott.emp(empno,ename) values('20','donghot');
    end;
    /  --完成并执行
    
    --注意权限不足的问题insufficient privileges:每个用默认情况下只能在自己的方案下执行PLSQL
    /*注意: 1 你的数据要你的表结构匹配,(数据的个数要够,数据类型也要匹配):ORA-00947: not enough values
            2 数据和你的约束匹配
    */    

    通过上面的代码我们简单的认识了添加存储过程的代码;

     


     

    pl/sql函数:

      函数:用于返回特定的数据,在建立函数时,其头部必须包含return子句,在函数体内部必须包含return语句返回数据 

      案例:

    -- 创建函数实例
    create or replace function myfunction1(v_ename varchar2) return
    number is v_Ysal number(9,2);
    begin 
      select sal*12+nvl(comm,0)*12 into v_Ysal from emp where ename=v_ename;
      return v_Ysal;
    end;
    
    --PLSQL中调用函数
    var v_rev number;
    call myfunction1('SCOTT') into:v_rev;
    print v_rev;
    
    --java中调用函数
    select myfunction1('SCOTT') from dual;
    rs.getInt(1);--获取返回值

     


     

    pl/sql包:

      逻辑上组合过程和函数,有规范和包体两部分组成

      它是怎么调用的呢:

        当调用包中的过程或是函数时,在过程和函数前面需要带有包名,如果是其他方案的包,还需要包前面带方案名;

      来看看pl/sql增加包的案例吧!!!  

    --创建包实例
    --创建包规范
    create or replace package mypackage1 is
    procedure update_sal(name varchar2, newsal number);
    function annul_income(name varchar2) return number;
    end;
    /
    --此规范字包含了过程和函数的说明,但是没有过程和函数的实现代码.
    --所以需要重新建立包体,包体用于实现规范中的过程和函数
    create or replace package body mypackage1 is
    procedure update_sal(name varchar2,newsal number)
    is
    begin
        update c##scott.emp set sal = newsal where ename=name;
    end;
    --函数开始
    function annul_income(name varchar2)
    return number is
    return_salary number;
    begin
        select sal*12+nvl(comm,0) into return_salary from emp where ename=name;
        return return_salary;
    end;
    end;
    /
    --调用:
    --call/exec:包名.过程名(参数);
    call mypackage1.update_sal('SCOTT',199);
    --调用函数
    var v_rev number;
    call mypackage1.annul_income('SCOTT') into:v_rev;--试验是call可以,exec不行
    print v_rev;

     

     


     

     

    触发器:

      触发器是一个隐含执行的存储过程,当定义触发器是,必须要指定触发的事件和触发的操作,常用的触发事件包括insert,update,delete语句,触发操作对象实际是一个pl/sql块

      怎么创建触发器??老样子,我们主要看代码:

    create sequence seq01;
    create or replace trigger trig01
      after insert or delete or update on dept
    begin
      if inserting then
        insert into emp(empno,ename,hiredate) values (seq01.nextval,'insert', sysdate);
      elsif updating then
        insert into emp(empno,ename,hiredate) values (seq01.nextval,'update', sysdate);
      elsif deleting then
        insert into emp(empno,ename,hiredate) values (seq01.nextval,'delete', sysdate);
      end if;
    end;

     


     

     

    变量:

      标量类型:

        标量类型的定义方式:    

    定义一个变长字符串
        v_name varchar(10);
    定义一个小数,切默认值是3.14
        v_sal2 number(6,2):=3.14
    
    定义一个小数
        v_sal number(6,2);
    定义一个日期类型
        v_hiredate date;
    
    定义一个特布尔变量,不能为空,初始值为false
        v_valid boolean not null default false

        如以上,下面定义代码:

    --通过员工编号,显示姓名,工资,个税
    --税率为0.03
    declare
    --声明变量
    c_tax_rate number(3,2):=0.03;
    --v_name varchar2(5);--有可能小于查到的数据
    v_name emp.ename%type;--和数据所在列的数据类型一样; 变量名 表名.列名%type
    v_sal number(7,2);
    v_tax_sal number(7,2);
    begin
    --执行
    select ename,sal into v_name,v_sal from emp where empno=&no;
    --计算所得税
    v_tax_sal:=v_sal*c_tax_rate;
    --输出
    dbms_output.put_line('name:'||v_name||'  sal:'||v_sal||'  tax:'||v_tax_sal);
    end;

      符合变量类型:

        数据集合变量有数组和集合;

        pl/sql是干么用的??是用来保存多个值的变量,类和结构体的,如下可见....

    declare
    type emp_record_type is record( --定义一个数据类型(记录类型):包含3个数据,有三个数据及其类型
        name emp.ename%type,
        salary emp.sal%type,
        job emp.job%type);
        v_record emp_record_type;  --定义一个变量,数据类型是emp_record_type
    begin
        select ename,sal,job into v_record from emp where empno=7788;
        dbms_output.put_line('ename:'||v_record.name);
        dbms_output.put_line('sal:'||v_record.salary);
         dbms_output.put_line('job:'||v_record.job);
    end;

        sql表:相当于数组.但是plsql下标可以为负数,并且元素下标没有限制

        

      参照类型:

        参照变量:是指用于存放数值指针的变量.通过使用参照变量,可以使得应用程序共享相同对象,从而降低占用空间

        游标变量(ref cursor)(在我们工作中是用的最多的):

          使用游标有声明和使用,声明时不需要指定相应的select语句,但是当使用游标时,需要指定select语句,从而和selct语句绑定

          来个案例吧!!一看便知晓;条件:编写一个块,输入部门编号,显示部门所有员工和工资

     

     

        对象类型变量(ref obj_type)

     

      


     

    控制结构:

      条件语句:

        if...thien

        if...thien...else

        if...thien...elsif...else

    create or replace procedure myProcedure08(sNo number) is
    --create or replace procedure myProcedure
    v_job emp.job%type;
    begin
    select job into v_job from emp where empno=sNo;
    if v_job='PRESIDENT' then
    update emp set sal=sal+1000 where empno=sNo;
    --elseif v_job='MANAGER' then
    --else if v_job='MANAGER' then
    elsif v_job='MANAGER' then
    update emp set sal=sal+500 where empno=sNo;
    else
    update emp set sal=sal+200 where empno=sNo;
    end if;
    end;
    /

     

     

     

      循环语句:

        loop

        while

        for

      这里我们就不代码举列了....

     

      循序控制语句:

        goto:goto语句(强烈建议不用),无用

        null:null语句不会执行任何语句操作,并且会直接将执行传递到下一句;增加程序的可读性;

    异常:

      来看看处理Oracle常见的异常:  

     

    declare
    v_ename emp.ename%type;
    begin
      --
      select ename into v_ename from emp where empno=&eno;
      dbms_output.put_line('name: '|| v_ename);
      exception 
        when no_data_found then
          dbms_output.put_line('no found a');
      end;

     

    例外:

      处理与Oracle无关的例外

    create or replace procedure ex_test(nu number)
    is
    begin
      update emp set sal=sal+1000 where empno=nu;
      end;
    
    
    
    create or replace procedure ex_test(nu number)
    is
    --定义一个例外
    myex exception;
    begin
      update emp set sal=sal+1000 where empno=nu;
      --sql%不表示没有update
      if sql%notfound then
        raise myex; --SQL> --raise myex:触发myex
        end if;
        exception
        when myex then
          dbms_output.put_line('m没用用户更新');
       
      end;

     


     

    视图:

      视图就是一张虚拟表其内容由查询定义(SQL查询定义).和真的数据表一样,包含一系列带有名称的列和行数据.但是,视图并不在数据库中,以储存的数据值集形式存在啊

      视图特性:不需要占用磁盘空间,表的区别;视图不能添加索引;使用视图可以简化复杂查询(多表联查);有更高的安全性,不同级别看不同的视图;视图本质上一张内存缓存表,所以和表不能重名

      增加视图:create view 视图名 as select 语句 with [read only]

      修改视图:create or replace view 视图名 as select 语句 with [read only]

      删除视图:drop view 名字

     


     

    序列:

      oracle特有的,产生唯一的不间断的数字序列,用作表的主键

      

     


     

    PL/SQL分页:

      下面就不啰嗦了,直接上代码实现:

     

    --oracle分页:
      select * from emp;
      select t1.*,rownum rn from (select * from emp) t1;
      select t1.*,rownum rn from (select * from emp) t1 where rownum<=10;
      --分页模版
      select * from 
      (select t1.*,rownum rn from (select * from emp) t1 where rownum<=10)
       where rn>=6;
       
       
    create or replace procedure Paging
    (
    tableName in varchar2, --查询的表的名称
    rowCount out number,   --查询到的总记录数
    pageSize in number,    --每页显示数
    pageCount out number,  --总页码数   := rowCount/pageSize;
    pageNow in number,     --当前页码数
    page_cursor out PackagePaging.page_cursor --返回数据的结果集,jav边遍历然后输出到html页面中
    ) is
    --定义变量
    v_sql varchar2(1000);
    --定义两个整数,用于查询时候的起始数据行和结束数据行
    v_begin number:=pageSize*(pageNow-1)+1;          --起始的那个rowCount,起始那个数据的下标
    v_end number:=pageSize*pageNow;                 --当前页的最后一个数据
    ---------------------------------------------
    begin
    v_sql:='select * from (select t1.*,rownum rn from (select * from '||tableName||') t1 where rownum<='||v_end||')  where rn>='||v_begin;--||';';
    --v_sql:='select * from emp';
    --给当前SQL语句的结果集绑定一个游标
    open page_cursor for v_sql;
    --------------------------------------------
    --查询一共有多少个结果
    v_sql := 'select count(*) from '|| tableName;
    --执行SQL语句,把返回的值赋值给rowCount
    execute immediate v_sql into rowCount;
    --计算pageCount
    if mod(rowCount,pageSize)=0 then
      pageCount:=rowCount/pageSize;
    else
      pageCount:=rowCount/pageSize+1;
    end if;
    --关闭游标
    --close page_cursor;
    end;

     

     

     


     

     

    PL/SQL无限分类:

      如下:

    drop table category;

    --要点一:子类的pid必须是父类等于父类的id
    create table category(
    id number(10) primary key,
    name varchar2(50),
    pid number(10),
    isleaf number(1),--0 代表非叶子节点,1代表叶子节点,
    clevel number(2)
    );

    --cherub模拟数据
    --要点二:模拟数据必须满足这个二维结构
    insert into category values (1, 'book1',0,0,0);
    insert into category values (2, 'book2',1,0,1);
    insert into category values (3, 'book3',2,1,2);
    insert into category values (4, 'book4',2,0,2);
    insert into category values (5, 'book5',4,1,3);
    insert into category values (6, 'book6',1,0,1);
    insert into category values (7, 'book7',6,1,2);
    insert into category values (8, 'book8',6,1,2);
    insert into category values (9, 'book9',2,0,2);
    insert into category values (10, 'book10',9,1,3);

    create or replace procedure myProCat (
    v_pid category.pid%type,
    v_level binary_integer

    ) is
    cursor c is select * from category where pid = v_pid; -- 要点:每次去满足这个条件,然后再把每条条数据中id传入到自己作为pid去查得下面的数据
    v_preStr varchar2(1024) :='';
    begin
    for i in 0..v_level loop
    v_preStr := v_preStr || '--';
    end loop;

    --要点三:递归函数的书写和调用
    --要点四:pl/sql 增强for循环的问题
    for v_category in c loop --就是一个增强的for循环,v_category的结果相当于是个集合
    dbms_output.put_line( v_preStr||v_category.name);
    if(v_category.isleaf=0) then
    myProCat(v_category.id,v_level+1);
    end if;
    end loop;
    end;

    以上就是PL/SQL的基本原理与操作

         

  • 相关阅读:
    第四次作业
    第二次上机作业
    5.21上机作业
    第十一周课后作业
    第十一周上机练习
    第10周java作业
    第9次上级联系
    第8周作业
    第八周上机练习
    第七周作业
  • 原文地址:https://www.cnblogs.com/xcxcxc/p/4681397.html
Copyright © 2011-2022 走看看