zoukankan      html  css  js  c++  java
  • Oracle学习之二 PL/SQL块编程基础

    1、PL/SQL块简介

    块(Block)是PL/SQL的基础程序单元,编写PL/SQL程序实际就是编写PL/SQL块。要完成相对简单的应用功能,可能只需要一个PL/SQL块;而如果要实现复杂的应用功能,那么可能需要一个PL/SQL块中潜逃其他PL/SQL块。编写PL/SQL应用模块,块的嵌套层次没有限制。

    PL/SQL是一种块结构语言,这意味着PL/SQL程序可以分为逻辑块。PL/SQL块由3个部分组成:定义部分、执行部分、异常处理部分。其中,定义部分用于定义变量、常量、游标、用户自定义异常、复杂数据类型等;执行部分用于实现应用模块功能,该部分包含了要执行的PL/SQL语句和sql语句;异常处理部分用于处理执行部分可能出现的运行错误。

    1.1PL/SQL块的类型

      ●匿名块

    所谓匿名块就是指没有名称的PL/SQL块。匿名块既可以内嵌到应用程序中,也可以在交互环境中直接使用。例如:

    declare
         v_avgsal number(6,2)
    begin
        select avg(sal) into v_avgsal  from emp where empno=&no;
         dbms_output.putline('平均工资'||v_avgsal  );
    end;

    ● 子程序

    子程序包括存储过程、函数、包。 通过将商业逻辑和企业规划集中到PL/SQL子程序中,可以简化客户端程序的开发和维护,并且提高应用程序性能。下面简单介绍一下各种子程序。
    ◆ 过程
     过程用于执行特定操作。当建立过程时,即可以指定输入参数,也可以指定输出参数。通过在过程中使用输入函数,可以将应用环境的数据传入到执行部分;通过使用输出参数,可以将执行部分的数据传递到应用环境。可以使用CREATE PROCEDURE命令建立过程,示例如下:
    create procedure update_sal(name varchar2,newsal number) is
    begin
        update emp set sal=newsal where ename=name;
    end;
    当调用该过程的时候,可以使用excute 或call命令。
    exec update_sal('scott',1000);
       call update_sal('scott',1000);
    ◆ 函数

    函数用于返回特定的数据。当建立函数时,在函数头部必须包含return 子句,而在函数体内必须包含return语句返回数据。可以使用create function 命令创建函数。

    create function annual_income(name vachar2) return number is
     annual_salary number(7,2);
    begin
        select sal*12 into annual_salary from emp where ename=name;
        return annual_salary ;
    end;
    ◆ 包

    包用于逻辑组合相关的过程和函数,它由包规范和包体两部分组成。包规范用于定义公用的变量、常量、过程和函数。可以使用create package命令创建包规范。

    create package emp_pkg is 
           procedure update_sa(name varchar2,newsal number);
           function annual_income(name varchar2) return number;
       end;

    包规范中只包含了过程和函数的说明,而没有过程和函数的实现代码。包体用于实现包规范中的过程和函数,建立包体可以使用create package body 命令。

    create package body emp_pkg is 
           procedure update_sa(name varchar2,newsal number) is
       begin
           update emp set sal=newsal where ename=name; 
      end;
           function annual_income(name varchar2) return number is
           annual_salary number(7,2); 
          begin 
            select sal*12 into annual_salary from emp where ename=name; 
            return annual_salary ; 
         end;
     end;

    当调用包的过程和函数时在过程和函数名之前必须要带有包名作为前缀(包名.子程序名)。而如果要调用其他schema的包,还必须要加上Schema名作为前缀。

    ● 触发器

    触发器是指隐含执行的存储过程。当定义触发器的时候,必须指定触发事件以及触发操作,常用的触发事件包含insert 、update 和delete语句,而触发操作实际是一个PL/SQL块,建立触发器是使用 create trigger命令来完成。

    create triggerupdate_cascade after update on dept for each row 
    begin
        update emp set deptno=:new.deptno where deptno=:old.deptno;
    end;

    2、数据类型与变量

    编写PL/SQL程序时,若临时存储数值,必须要定义变量和常量;若在应用程序和子程序之间传递数据,必须要为它们指定数据类型。在编写PL/SQL程序时,可以使用标量类型、复合类型、引用类型和LOB类型四种类型。

    2.1 标量变量

    标量变量是指只能存入单个数值的变量。最常用的变量就是标量变量。当定义标量变量时,必须要指定标量的数据类型。标量数据类型包括数字类型、字符类型、日期类型和布尔类型。

    (1) 常用标量数据类型

    常用的标量类型包括:

    VARCHAR2(n):该数据类型用于定义可变长度的字符串,其中n表示指定字符串的最大长度,其最大值为32767字节。

    CHAR(n):该数据类型用于定义固定长度的字符串,其中n表示指定字符串的最大长度,其最大值为32767字节。如果没有指定n,则其默认值为1.

    NUMBER(p,s): 定义固定长度的整数和浮点数,p表示精度,用于指定数字的总位数;s表示标度,用于指定小数点后的数字位数.

    DATE: 用于定义日期和时间数据,其数据长度固定为7字节。

    TIMESTAMP:  Oracle9i中新增的数据类型,用于定义日期和时间数据。幅值的方法和date相同,但显示数据的时候不仅会显示日期,而且还会显示时间和上下午标记。

    LONG和LONG RAW:  long数据类型用于定义变长字符串,类似于varchar2,但其字符串最大长度为32760字节;long raw 用于定义变长的二进制数据,其数据最大长度为32760字节。

    BOOLEAN: 用于定义布尔变量,其变量值为true,false或null。

    BINARY_INTEGER: 用于定义整数,其数值范围在-2147483647和 2147483647之间。

    BINARY_FLOAT 和 BINARY_DOUBLE: 分别用于定义单精度的浮点数和双精度的浮点数。这两种数据类型主要用于高速的科学运算,当为BINARY_FLOAT 赋值时应该带有后缀f(1.5f),当为BINARY_DOUBLE赋值时,应该带有后缀d(3.23d)。

    (2) 定义标量变量

    如果要引用标量变量,必须首先在定义部分定义,然后才能在执行部分或异常部分使用这些标量变量。

    identifier [CONSTANT] datatype [not null] [:=|default expr]

    identifier :用于指定变量或常量的名称。

    CONSTANT:用于指定常量。当定义常量时。必须指定它的初始值,并且数据不能改变。

    datatype:用于指定变量或常量的数据类型。

    not null:用于强制初始化变量(不能为null) ,当指定not null时,必须要为变量提供数值。

    := :用于为变量或常量指定初始值。

    expr: 用于指定初始值的PL/SQL表达式,可以是文本、其他变量、函数等。

    (3) 使用标量变量

    在定义部分标量变量之后,在执行部分和异常处理部分可以引用这些标量变量。在PL/SQL中为变量赋值不同于其他语句,必须要在等号前面加冒号(:=)。

    declare
     v_ename varchar2(5);
    v_sal number(6,2);
    c_tax_rate CONSTANT number(3,2) :=0.03;
    v_tax_sal number(6,2);
    begin
        select ename,sal into v_ename,v_sal from emp where empno=&no;
        v_tax_sal:= v_sal*c_tax_rate;
         dbms_output.putline(v_tax_sal);
    end;

    (4) 使用%TYPE属性

    当PL/SQL变量存储列值时,必须确保变量使用合适的数据类型和长度,否则在运行的过程中可能出现PL/SQL运行错误。为了避免这种不必要的错误,可以使用PL/SQL属性来定义变量。当使用%TYPE属性定义变量时,它会按照数据库列或者其他变量来确定新变量的类型和长度。

    declare
        v_ename emp.ename%TYPE;
        v_sal emp.sal%TYPE;
    c_tax_rate CONSTANT number(3,2) :=0.03;
       v_tax_sal v_sal%TYPE;
    begin
           select ename,sal into v_ename,v_sal from emp where empno=&no;
           v_tax_sal:= v_sal*c_tax_rate;
           dbms_output.putline(v_tax_sal);
       end;

    2.2 复合变量

    复合变量是指用于存放多个值的变量。在使用复合变量时,必须先用TYPE进行定义。当定义复合变量时,必须要使用PL/SQL的复合数据类型。PL/SQL的复合数据类型有:PL/SQL记录类型、PL/SQL集合类型(包括PL/SQL表、嵌套表以及varray)等四种。这四种类型分别在不同的情况下应用:处理单行单列数据时,用标量变量;处理单行多列数据时,使用PL/SQL记录;处理单列多行数据时,使用集合;处理多行多列数据时,使用PL/SQL记录和集合。

    1) 、PL/SQL记录(RECORD)

    PL/SQL记录类似于高级语言中的结构,每个PL/SQL记录一般包含多个成员,它用于简化处理单行多列的数据。

    PL/SQL记录的定义有两种方法。第一种方法,先使用TYPE..IS RECORD 自定义记录类型,然后定义记录变量。第二种,使用表名%ROWTYPE属性直接定义记录变量。记录变量定义完成后,可以通过‘记录变量.记录成员’的形式来引用记录成员。

    TYPE emp_recore_type IS RECORD(
    name emp.ename%type,
    salary emp.sal%type,
    title emp.job%type);
    emp_record emp_record_type;

    以下是使用表名%ROWTYPE属性定义的记录变量:

    emp_record emp%ROWTYPE

    给记录变量赋值的方法有两种:一种时利用赋值语句给每个成员分别赋值;一种时通过SELECT…INTO 语句赋值,例如:

    emp_record.ename:='scott'SELECT * INTO emp_record FROM emp WHERE eno=788;

    用SELECT…INTO 语句赋值时,select语句中的列名列表的名称和个数以及类型必须与记录变量的成员个数、名称、类型完全相同。

    2) 、集合类型

    PL/SQL集合类型时类似于高级语言数组的一种复合数据类型,包括PL/SQL表、嵌套表和变长数组三种类型。

    PL/SQL表

    PL/SQL表也称索引表,它与高级语言数组不同的是:高级语言数组的下标不能为负,但是PL/SQL表的下标可以是负数;高级语言数组的元素个数有限制,而PL/SQL表的元素个数没有限制,并且下标没有上下限。

    嵌套表

    嵌套表与PL/SQL表不同的是:高级语言数组和嵌套表的下标都不能为负;高级语言的元素个数是有限制的,而嵌套表的元素个数没有限制。嵌套表和PL/SQL表非常类似,但嵌套表可以使用列的数据类型,而PL/SQL表不能作为表列的数据类型。当在表列中使用嵌套表时,必须使用create type语句建立嵌套表类型。

    VARRAY

    VARRAY(变长数组)类似于嵌套表,它可以作为表列和对象类型属性的数据类型。但要注意,嵌套表的元素个数没有限制,而varray的元素个数是有限制的。

    集合类型的内置方法

    集合变量有很多内置方法,其调用格式为:集合类型变量.方法。

    表2-1中列出了Oracle集合类型常用的方法。

    表2-1 集合类型的方法

    方法

    描述

    使用限制

    COUNT 返回集合中的元素个数  
    DELETE 删除集合中所有元素  
    DELETE(x) 删除集合中下标为x的元素,如果x为null,则保持不变 对VARRAY非法
    DELETE(x,y) 删除元素下标x到y的元素,如果x>y集合保持不变 对VARRAY非法
    EXIST(x) 如果集合元素x已经初始化,则返回true,否则返回false  
    EXTEND 在集合末尾添加一个元素 对索引表不合法
    EXTEND(x) 在集合末尾添加x个元素 对索引表不合法
    EXTEND(x,n) 在集合末尾添加元素n的x个副本 对索引表不合法
    FIRST 返回集合中的第一个元素的下标,对于varray集合始终返回1。  
    LAST 返回集合中的最后一个元素的下标,对于varray集合返回值始终等于COUNT。  
    LIMIT 返回varray集合的最大元素个数 对于嵌套表和索引表集合无用
    NEXT(x) 返回在元素x之后及紧挨着它的元素的值,如果该元素是最后一个元素,则返回null  
    FRIOR(x) 返回在元素x之前紧挨着它的元素的值,如果该元素是第一个元素,则返回null  
    TRIM 从集合末端开始删除一个元素 对索引表不合法
    TRIM(x) 从集合末端开始删除x个元素 对索引表不合法

    2.3 引用变量

    引用变量是指用于存放数值指针的变量。通过使用引用变量可以使得应用程序共享相同对象,从而降低占用空间。可以使用游标变量(REF CURSUR)和对象类型变量REF ojb_type 两种引用变量类型。

    1)、REF CURSUR

    当使显式游标时,需要在定义显式游标时指定响应的select语句,这种显式游标称为静态游标。当使用游标变量时,在定义游标变量时不需要指定select语句,从而实现动态游标操作。

    2)、REF ojb_type

    当编写对象类型应用时,为了共享相同对象,可以使用REF引用对象类型,REF实际是指向对象实例的指针。

    2.4 LOB变量

    LOB变量是指用于存储大批量数据的变量。Oracle将LOB分为两种:内部LOB和外部LOB。内部LOB包括CLOB/BLOB/和NCLOB三种类型。他们的数据被存储在数据库中,并且支持事务操作(提交、回滚、保存点)。外部LOB只有BFILE一种类型,该类型的数据被存储在操作系统文件中,并且不支持事务操作。其中,CLOB和NCLOB用于存储大批量字符数据,BLOB存储大批量二进制数据,而BFILE则存储指向操作系统文件的指针。

    3、编写PL/SQL代码

    3.1 注释

    注释用于解释当行代码或者多行代码的作用,从而提高了PL/SQL程序的可读性。

    ☆ 单行注释

    使用“--”符号注释单行代码

    ☆ 多行注释

    使用“/*..*/”注释多行代码

    3.2 PL/SQL代码编写规则

    1)标识符命名规则

    当在PL/SQL中使用标识符定义变量、常量时,标识符名称必须以字符开始,并且长度不能超过30个字符。

    2)大小写规则

    关键字大写,数据类型大写,标识符和参数小写,数据库对象和列小写。

    3)代码缩进

    同级代码对齐,下级代码缩进。

    所有文章都会同步发布到我的独立博客上 imsense.site 欢迎点击

    宝剑锋从磨砺出,梅花香自苦寒来。

    如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】按钮。

    如果,您希望更容易地发现我的新博客,不妨关注一下或者分享一下。

    未注明转载的文章,版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    【html5构建触屏网站】之touch事件
    优化网站加载速度的14个技巧
    存储
    [概念] javascript构造函数和普通函数的
    nodejs中的 Cannot read property'text' of undefined 问题
    整理js继承
    清除浮动的五种方法
    用canvas绘制一个时钟
    javascript运动框架
    $(document).ready()与window.onload的区别(转发)
  • 原文地址:https://www.cnblogs.com/lslvxy/p/3058556.html
Copyright © 2011-2022 走看看