[连载]Oracle 12cR2 PL/SQL语言参考 - 01 PL/SQL概览

330 阅读11分钟

1.1 PL/SQL的好处

1.1.1 与SQL紧密集成(Tight Integration wiht SQL)

PL/SQL与SQL的紧密集成体现在如下几点:

    1. PL/SQL可以使用所有的SQL数据操作,如游标控制语句,事务控制语句,所有的SQL函数,操作符,以及伪列
    1. PL/SQL完全支持SQL的数据类型,无需进行数据类型转换
    1. PL/SQL可以执行SQL查询并对查询结果进行处理
    1. PL/SQL函数可以在SELECT语句的WITH子句中定义和声明 PL/SQL同时支持 静态SQL 和 动态SQL:
    1. 静态SQL: 在编译时就已完全确定了SQL语句的内容
    1. 动态SQL: 必须要到运行时才能完全确定SQL语句的内容,让你的程序更灵活

1.1.2 高性能(High Performance)

绑定变量(Bind Variables)

当你在PL/SQL代码中嵌入SQL语句(INSERT,UPDATE,DELETE,MERGE或SELECT)时,PL/SQL编译器会将WHERE子句或VALUES子句中的变量转换为绑定变量,当运行相同的代码时(可能只是变量的值不同)可以重用这些语句,以提高性能

子程序(Subprograms)

PL/SQL子程序以可执行的形式存储在数据库中,并且可以重复调用.因为子程序在数据库服务器内部执行,
所以可以有效降低网络流量和改善响应时间子程序可以被缓存,并在用户间共享,这可以降低内存的使用和调用开销

优化器(Optimizer)

PL/SQL优化器可以重排代码,以获得更好的性能

1.1.3 高生产力(High Productivity)

PL/SQL有很多可以节省设计和排错的特性,并且在所有环境中都是如此
PL/SQL可以让你使用紧凑的代码来操作数据

1.1.4 可移植(Portability)

PL/SQL是可移植的和标准的,可以在任何运行Oracle数据库的操作系统及平台上运行

1.1.5 可伸缩(Scalability)

通过集中在数据库服务器上运行,PL/SQL增加了伸缩性共享内存让Oracle数据库可以在一个节点上支持数千个并发用户
另外,你还可以使用Oracle连接管理器来复用网络连接

1.1.6 可管理(Manageability)

由于你只需要在数据库服务器上集中维护一份PL/SQL子程序,而不是在各个客户端,所以PL/SQL子程序增加了可管理性

1.1.7 支持面向对象编程(Support for Object-Oriendted Programming)

PL/SQL允许你定义对象类型,以便在面向对象设计中使用

1.2 PL/SQL的主要特色

PL/SQL结合了SQL的数据处理能力和过程编程语言的控制能力,和别的过程编程语言一样,PL/SQL让你可以定义常量和变量,控制程序流程,定义子程序,捕获程序错误
你可以把复杂的程序切分为多个易于理解的子程序,并在多个应用中复用它们

1.2.1 错误处理(Error Handling)

PL/SQL使发现和处理错误变得更容易,当错误发生时,PL/SQL会抛出一个异常,程序的正常运行会停止,并把控制权传递给PL/SQL代码块中的异常处理部分,这可以使你不必像C语言那样,要自己确保每个操作步骤都去检查是否成功

1.2.2 块(Blocks)

PL/SQL代码的基本单元是块,它把相关的声明和语句组织在一起
一个PL/SQL块由一系列关键字: DECLARE, BEGIN, EXCEPTION 和 END 组成,它们把代码块分隔成了"声明"部分,"执行"部分和"异常处理"部分,只有"执行"部分是必需的
代码块可以有一个标签
代码块中的声明部分是本地变量,当代码块执行完成后,它们就消失了,这有助于避免使代码块和子程序的命名空间产生混乱
代码块可以嵌套: 因为一个代码块就是一个可执行语句,所以它可以出现在任何允许可执行语句存在的地方
你可以在交互式工具(例如SQLPlus或Enterprise Manager)中提交代码块,或者将其内嵌入Oracle Precompiler及OCI程序,代码块将执行一次,并且并不存入数据库,所以,我们称之为匿名块(anonymous block)(即使它拥有一个标签)
匿名块在加载入内存时被编译,它的编译分为三个步骤:

    1. 语法检查: PL/SQL语法被检查,同时产生一个解析树(parse tree)
    1. 语义检查: 类型检查,以及在解析树上的进一步处理
    1. 产生代码
注意: 一个匿名块就是一个SQL语句

代码块的样例

    <<label>>  -- 可选
    DECLARE  -- 可选
        -- 在这里声明本地类型,变量,和子程序
    BEGIN  -- 必需的部分
        -- 执行语句,可以使用DECLARE部分声明的类型,变量,子程序
    EXCEPTION  -- 可选
        -- 异常处理代码
    END;

1.2.3 变量和常量(Variables and Constants)

PL/SQL让你可以声明变量和常量,然后在表达式中使用它们,代码运行时,变量的值可以被改变,而常量的值不可以改变

1.2.4 子程序(Subprograms)

一个PL/SQL子程序是一个命名的PL/SQL代码块,而且可以被重复调用
如果子程序有参数,那么每次调用时可能会产生不同的结果,PL/SQL有两种子程序: 存储过程和函数,函数可以有返回值
PL/SQL也允许你调用外部的使用其他语言编写的程序

1.2.5 包(Packages)

包是在逻辑上将相关的PL/SQL类型,变量,常量,子程序,游标,异常等组织起来的模式对象
包会被编译并存储在数据库里,你可以将它认作是一个应用程序
你可以写自己的包,也可以使用Oracle提供的包

1.2.6 触发器(Triggers)

触发器是存储在数据库里的一个命名PL/SQL单元,用来响应发生的某种数据库事件(event)
你可以为事件指明是在事件发生前还是发生后运行触发器,是为整个事件运行一次触发器,
还是为事件所影响的每一行数据运行一次触发器

1.2.7 输入与输出(Input and Output)

大部分PL/SQL的输入与输出都与SQL语句有关.其他的PL/SQL输入输出由Oracle提供的系统包来支持

  • DBMS_OUTPUT
    显示输出,对输出debug信息很有用
  • HTF (Has Hypertext Function)
    产生HTML标签
    例如HTF.ANCHOR可以输出HTML的<a>标签
  • HTP (Has Hypertext Procedure)
    产生HTML标签
  • DBMS_PIPE
    让在同一个实例内的不同会话可以通信
  • UTL_FILE
    读写操作系统中的文件
  • UTL_HTTP
    可以发出HTTP请求,使用HTTP协议访问Internet
  • UTL_SMTP
    发送电子邮件
    要想让DBMS_OUTPUT输出显示,需要使用另一个程序,例如SQLPlus,同时,在SQLPlus交互环境里必须提前
    设置 SET SERVEROUTPUT ON
    上面的包程序无法直接从键盘获取数据,必须使用SQLPlus交互环境里的命令PROMPT和ACCEPT

1.2.8 数据抽象(Data Abstraction)

数据抽象可以让你处理数据的关键信息,而不必太过于关注细节
你可以先定义一个数据结构,然后再设计操作它的算法

  • 游标(Cursors)
    一个游标指向了你正在处理的SQL语句或PL/SQL的SELECT INTO语句所涉及的数据区域
    你可以使用游标,一次一行的来获取结果集中的数据,你还可以使用游标的一些属性,
    例如获知SQL语句影响了多少行数据
  • 复合变量(Composite Variables)
    复合变量有内部成员,你可以独立的访问它
    你可以将复合变量作为一个参数传递给子程序,PL/SQL有两种复合变量:
    集合(collection)
    记录(records)
    在集合中,所有元素都具有相同的数据类型,被称为元素(elements),你可以使用下标索引来访问这些元素
    列表或数组是集合的典型例子
    在记录中,各个元素可以拥有不同的数据类型,被称为域(fields),你可以通过名称来访问这些域,
    一个记录变量可以存放一个表的一整行字段数据,或者一行中的部分字段数据
  • 使用%ROWTYPE属性
    %ROWTYPE属性可以声明一个记录,用于表示一个数据库表或视图的一整行或部分行字段
    对于一整行或部分行的字段,记录内都有对应的域(field)与之同名和相同的数据类型,
    如果数据库表的字段结构变了,记录也会发生相应的变化
  • 使用 %TYPE 属性
    %TYPE 属性可以声明一个数据项,与之前声明过的变量或表的某个字段具有相同的数据类型
    这对于声明一个变量用于存放数据库表字段的值特别有用
  • 抽象数据类型
    抽象数据类型(Abstract Data Type, ADT)由一个数据结构和子程序组成,子程序用来操作数据
    构成ADT的变量称为属性(attributes),而操作那些属性子程序称为方法(methods)
    ADT存储在数据库中,ADT的实例可以存储在表中,也可以被用作PL/SQL变量
    在数据字典视图 *_OBJECTS 中,ADT在TYPE这个字段上的值为 TYPE ,
    而在静态数据字典视图 *_TYPES 中,ADT在TYPECODE这个字段上的值为 OBJECT

1.2.9 控制语句(Control Statements)

控制语句是PL/SQL对SQL的最重要的扩展
PL/SQL有三种控制语句:

  • 条件选择语句
  • 循环语句
  • 顺序控制语句

1.2.10 有条件编译(Conditional Compilation)

有条件编译让你可以在不移除代码的前提下定制程序功能
例如,你可以:

  • 在最新版本的数据库上运行时,使用最新的特性,但如果在旧版本的数据库上运行则禁用这些特性
  • 在开发环境下激活debug或跟踪语句,而如果在生产环境下运行则隐藏它们

1.2.11 对查询结果集一次处理一行(Processing a Query Result Set One Row at a Time)

PL/SQL允许你执行SQL查询,并对返回的结果集进行一次性处理
你可以使用一个基本循环语句,或者使用独立的查询,获取结果集,处理语句,来更精细的控制处理过程
下面是一个使用基本循环语句的例子

BEGIN
    FOR someone IN (
        SELECT * FROM employees
         WHERE employee_id < 120
         ORDER BY employee_id
    )
    LOOP
        DBMS_OUTPUT.PUT_LINE('First name = ' || someone.first_name ||
                             ', Last_name = ' || someone.last_name);
    END LOOP;
END;
/

1.3 PL/SQL的架构

1.3.1 PL/SQL引擎(PL/SQL Engine)

PL/SQL的编译和运行时系统是编译和运行PL/SQL程序单元的引擎
这个引擎可以安装在数据库中,或者安装在应用开发工具中,例如Oracle Forms
PL/SQL引擎可以接受任何有效的PL/SQL程序单元,它会运行过程语句,但是会把SQL
语句发送给数据库中的SQL引擎来执行

1.3.2 PL/SQL单元与编译参数(PL/SQL Units and Compilation Parameters)

PL/SQL程序单元会受到PL/SQL编译参数(数据库初始化参数中的一部分)的影响,不同的PL/SQL程序单元(例如包的包头和包体)可以有不同的编译参数设置
PL/SQL程序单元有如下这些:

  • PL/SQL匿名块(PL/SQL anonymous block)
  • 函数(FUNCTION)
  • 库(LIBRARY)
  • 包(PACKAGE)
  • 包体(PACKAGE BODY)
  • 存储过程(PROCEDURE)
  • 触发器(TRIGGER)
  • 类型(TYPE)
  • 类型体(TYPE BODY) 下面概述了PL/SQL编译参数,如果想针对某个程序单元来获取这些参数的值,可以查询静态数据字典ALL_PLSQL_OBJECT_SETTINGS
  • PLSCOPE_SETTINGS
    控制着PL/SQL源码文本的标识符数据在编译时的收集,交叉引用和存储,被PL/Scope工具所使用
  • PLSQL_CCFLAGS
    让你可以独立控制每个PL/SQL程序单元的有条件编译
  • PLSQL_CODE_TYPE
    为PL/SQL程序单元指定编译模式: INTERPRETED(默认值)和NATIVE
    如果"优化级别"小于2,那么:
    编译器产生解释型代码,不管PLSQL_CODE_TYPE的设置
    如果你指明了NATIVE,编译器会警告你,NATIVE被忽略
  • PLSQL_OPTIMIZE_LEVEL
    指明了编译PL/SQL程序单元时的优化级别(级别越高,编译器会试图做更多的优化)
    当PLSQL_OPTIMIZE_LEVEL=1时编译器会生成PL/SQL debugger所使用的的代码
  • PLSQL_WARNINGS
    启用或禁用PL/SQL编译器的告警信息
  • NLS_LENGTH_SEMANTICS
    可以让你在创建CHAR和VARCHAR2类型字段时使用两种语义来表示长度:
    "字节数" 和 "字符数"
  • PERMIT_92_WRAP_FORMAT
    指明12.1版本的PL/SQL编译器是否可以使用9.2版本的PL/SQL编译器编译的包 要想显式重新编译一个PL/SQL程序单元,并且重用它的编译参数,你必须使用带有COMPILE子句
    和REUSE SETTINGS子句的ALTER语句