该文首先介绍PL/SQL的基本程序单元,然后从字符集开始,逐步介绍PL/SQL程序的词汇单元、语法规则、数据类型等。
PL/SQL块结构: 由定义部分、执行部分、异常处理部分组成
declare -- 定义[可选] /* 定义块中要使用的常量与变量等等 */ begin -- 块代码(执行部分)开始 /* 块代码编写处 */ exception -- 异常[可选] /* 异常处理代码 */ end; -- 块结构的结束,必须由;号结尾
PL/SQL块的类型:
匿名块:当次有效(only one)命名块:子程序(存储过程(procedure)、函数(function))、触发器(trigger)、包(package)
简单PL/SQL块示例:
-- 打开控制台的输出开关,不打开则无法输出,执行一次即可 set serveroutput on; begin -- dbms_output:系统包 -- put():输出不换行; put_line():输出并换行 dbms_output.put('你好 老八!'); dbms_output.put_line(''); dbms_output.put('你好 老六!'); dbms_output.put_line('你好 峰峰!'); end;
Oracle的字符集名字一般由以下部分组成:语言或区域、表示一个字符的比特位数、标准字符集名称(可选项,S或C,表示服务器或客户端)。Oracle字符集UTF8与UTFE不符合此规定,其它基本都是这种格式。
Oracle中的字符编码方案有单字节编码、多字节编码、Unicode编码三种方案。
- 单字节编码:
- 单字节7位字符集,可以定义128个字符,最常用的字符集为US7ASCII。
- 单字节8位字符集,可以定义256个字符,适合于欧洲大部分国家。例如:WEB8ISO8859P1表示西欧、8位、ISO标准8859P1编码。
- 多字节编码:
- 变长多字节编码:某些字符用一个字节表示,其它字符用两个或多个字节表示,常用于对亚洲语言的支持,例如:AL32UTF8字符编码中,AL代表ALL,指适用于所有语言。
- 定长多字节编码:每一个字符都使用固定长度字节的编码方案,目前Oracle唯一支持的定长多字节编码是AF16UTF16,也是仅用于国家字符集。
- Unicode编码:Unicode为每一个字符提供唯一的编码。
- UTF-16是Unicode的16位编码方式,是定长多字节编码,用2个字节表示一个Unicode字符,F16UTF16是UTF-16编码字符集。
- UTF-8是Unicode的8位编码方式,是变长多字节编码,可以用1、2、3、4个字节表示一个Unicode字符,AL32UTF8、UTF8、UTFE是UTF-16编码字符集。
如何选择合适的数据库字符集:
- 数据库需要存储的数据类型是字符集选择的首要考虑目标
- 字符集的选择需要优先考虑应用程序的需要
与字符集相关的问题:
- 在UTF8环境下运行SQL语句报错的问题
- 数据库出现乱码的问题
- 数据库字符集与客户端NLS_LANG设置不同引起的乱码
- 客户端NLS_LANG与本地化环境不同引起的乱码
编写PL/SQL程序时,可以使用标量类型、复合类型、引用类型、LOB类型等四种数据类型。
PL/SQL块中变量:先定义,后使用,注意命名以v_
开头,且注意变量的数据类型。
定义变量和常量的语法:
identifier [constant] datatype [not null] [:=|default expr] 标识符 [constant] 数据类型 [不能为null] [赋值 或 设置默认值 PL/SQL表达式] -- := :用于为变量或常量指定初始值 -- []:方括号表示该参数是可选的 -- constant:用于指定常量,当定义常量时,必须指定它的初始值,并且数据不能改变。 -- 如果在定义变量时没有指定初始值,那么变量初始值为NULL。
定义变量和常量的示例:
declare v_name varchar2(10); -- 定义一个varchar2类型的变量 v_sal number(6,2); -- 定义一个number类型的变量 v_balance binary_float; -- Oracle 10g 新数据类型,单精度浮点型 c_tax_rate constant number(3,2) := 5.5; -- 定义常量并赋值5.5 v_valid boolean not null default false; -- 定义布尔值,指定不能为null,指定默认值为false begin end;
标量变量是指只能存入单个数值的变量。需要先定义再使用。
字符类型:
char(n)
:定长字符串,它会用空格填充来达到其最大长度;n指定字符串的最大长度,如果没有指定n,则其默认值为1;表列类型最大4000字节,PL/SQL块中变量类型最大32767字节。varchar2(n)
:变长字符串,它不会用空格填充来达到其最大长度;n指定字符串的最大长度;表列类型最大2000字节,PL/SQL块中变量类型最大32767字节。long
:类似于varchar2,但其字符串的最大长度为32760字节long raw
:定义变长的二进制数据,其数据最大长度为32760字节
数值类型:
number(p,s)
:用于定义固定长度的整数和浮点数,关于number的有效位p和精确位(s)遵循以下规则:
p:是有效数据总位数,取值范围为【1-38】,默认值是38
s:表示精确到多少位,取值范围为【-84-127】,默认值是0
binary_integer
:定义整数,范围在-2147483647和2147483647之间。在Oracle9i之前,当定义PL/SQL表时,必须使用该类型作为下标的数据类型。表列不能用该数据类型。binary_float 和 binary_double
:这两种类型是Oracle10g新增的数据类型,分别用于定义单精度浮点数和双精度浮点数,主要用于高速的科学计算。为binary_float类型变量赋值时,应带后缀f,为binary_double类型变量赋值时,应带后缀d
日期类型:
date
:定义日期和时间数据,占用7个字节的存储空间,日期数据类型具有特殊关联的属性。Oracle 为每个日期值存储以下信息: 世纪、 年、 月、 日期、 小时、 分钟和秒timestamp
:Oracle 9i新增,定义日期和时间数据,占用7或12个字节的存储空间。它与date数据类型不同,因为timestamp可以包含小数秒,带小数秒的timestamp在小数点右边最多可以保留9位。显示该类型变量时,不仅会显示日期,还会显示时间和上下文标记。
布尔类型:
boolean
:用于定义布尔变量,值为true、false、null。表列不能采用该类型!
使用标量变量和
%type
属性的示例:
declare -- %type会按照数据库列或其它变量来确定新变量的类型和长度 v_name emp.ename%type; v_sal number(7,2); -- &符号表示键盘输入,v_no number := &no; 表示将键盘输入的值赋到变量v_no中,no是键盘输入的提示信息 v_no number := &no; begin select ename,sal into v_name,v_sal from emp where empno=v_no; dbms_output.put_line('员工名:'||v_name); dbms_output.put_line('薪水:'||v_sal); exception when no_data_found then dbms_output.put_line('emp表中没有该员工!'); end;
复合变量是指用于存放多个值的变量。 使用复合变量时,必须先用
type
定义类型,然后再用该类型定义变量
PL/SQL中的复合类型有:PL/SQL记录类型、PL/SQL集合类型(包括PL/SQL表、嵌套表、varray) 等四种。
不同情况下的应用场景:
- 处理单行单列数据:用标量变量
- 处理单行多列数据:用PL/SQL记录
- 处理单列多行数据:用集合
- 处理多行多列数据:可以结合使用PL/SQL记录和集合
类似于高级语言中的结构,每个PL/SQL记录一般都包含多个成员,它用于简化处理
单行多列
的数据。
PL/SQL记录的定义与赋值:
declare -- 第一种:先使用type...is record自定义记录类型,然后定义记录变量。 type emp_record_type is record( -- 定义记录类型 names emp.ename%type, salary emp.sal%type, jobs emp.job%type); emp_record emp_record_type; -- 定义记录变量 -- 第二种:当记录类型中数据个数及类型与某个表的字段个数及类型完全相同时,可以使用表名的%rowtype属性直接定义记录变量。 emp_record2 emp%rowtype; begin -- 第一种:用赋值语句给每个成员分别赋值(单个赋值) emp_record.names := 'scott'; -- 第二种:通过select...into语句赋值(整体赋值:要注意二者之间的字段个数与数据类型要一致) select * into emp_record2 from emp where empno = 7788; dbms_output.put_line(emp_record2.ename); -- 输出SCOTT end;
PL/SQL表也称索引表,类似于高级语言中的数组,但是它的
下标可以为负
,元素个数没有限制
,下标没有上下限
。必须先定义PL/SQL表类型再定义PL/SQL表变量,然后才能使用PL/SQL表。
定义与使用:
declare -- A:先定义类型 type emp_table_type is table of emp.sal%type index by binary_integer; -- B:再定义数组 salary_array emp_table_type; begin salary_array(-66) := 3000; -- 赋值 select sal into salary_array(66) from emp where empno = 7839; dbms_output.put_line(salary_array(-66)); -- 3000 dbms_output.put_line(salary_array(66)); -- 5000 dbms_output.put_line(salary_array(-5)); -- 报错:no_data_found end;
嵌套表与PL/SQL表非常类似,但嵌套表
下标不可以为负并且可以作为表列的数据类型
,而PL/SQL表不能作为表列的数据类型。使用前需先用create type
语句建立嵌套表类型。
使用示例:
-- 创建对象类型 create or replace type emp_type as object( name varchar2(20), salary number(7,2) ); -- 以该类型创建PL/SQL表类型 create or replace type emp_array is table of emp_type; -- 创建新表(存储表)deptartment create table deptartment( deptno number(2) primary key, dname varchar2(10), employee emp_array )nested table employee store as employee; -- employee它就是嵌套在deptartment中的表,也就是它和主表deptartment之间是主从关系,即一条主表记录对应一个嵌套表 -- 插入数据 insert into deptartment(deptno,dname,employee) values(1,'研发部',emp_array(emp_type('张三',5000),emp_type('王二狗',3000),emp_type('张麻子',2000))); insert into deptartment(deptno,dname,employee) values(2,'市场部',emp_array(emp_type('胡润',9000),emp_type('可乐',1500),emp_type('张麻子',2000),emp_type('刘六',7788))); insert into deptartment(deptno,dname,employee) values(3,'销售部',emp_array(emp_type('胡润',9000))); select * from deptartment; -- 查询显示出第一个部门中嵌套表的员工信息 select * from table(select employee from deptartment where deptno=1); -- 查询显示出第2个部门中嵌套表的员工姓名 select name from table(select employee from deptartment where deptno=2); -- 查询出所有信息 select d.deptno,d.dname,e.* from deptartment d,table(employee) e; -- 注:table是oracle提供的一个方法,可用于去掉集合的嵌套
varray(变长数组)
类似于嵌套表,它可以作为表列和对象类型属性的数据类型。嵌套表的元素个数是没有限制的,而varray的元素个数是有限制的。使用前必须先建立 varray 类型。
示例:
-- 创建对象类型article_type用于存储文章信息 create type article_type as object( title varchar2(30), pubdate date ); -- 创建varray类型article_array用于存储多篇文章信息,最多为20篇 create type article_array is varray(20) of article_type; -- 引用varray示例: create table author( id number(6), names varchar2(10), -- 引用article_array article article_array );
注意: 嵌套表列数据需要存储在专门的存储表中,而varray数据则与其它列数据一起存放在表段中。
方法 | 描述 | 使用限制 |
---|---|---|
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 | 返回VARRY集合的最大的元素个数 | 对于嵌套表和索引表无用 |
next(x) | 返回在元素x之后及紧挨着它的元素的值,如果该元素是最后一个元素,则返回null | |
prior(x) | 返回集合中在元素x之前紧挨着它的元素的值,如果该元素是第一个元素,则返回null | |
trim | 从集合末端开始删除一个元素 | 对索引表非法 |
trim(x) | 从集合末端开始删除x个元素 | 对索引表非法 |
引用变量是指用于存放数值指针的变量,主要有两种。
ref cursor (游标类型): 用来定义游标类型,在第六章做描述讲解。
ref obj_type (对象类型): 实际上是指向对象实例的指针。使用该变量主要是为了共享相同对象
示例1:假定每个家庭有四口人,当进行人口统计时,通过ref引用home_type使得同一家庭的成员可以共享家庭地址
-- 1:先建立对象类型home_type和对象表homes,然后插入数据 create or repalce type home_type as object( -- 创建对象类型 street varchar2(50),city varchar2(20) state varchar2(20),zipcode varchar2(6) owner varchar2(10) ); create table homes of home_type; -- 创建homes表 insert into homes values('呼伦北路12号','呼和浩特','内蒙','0100010','李四'); insert into homes values('呼伦北路13号','呼和浩特','内蒙','0100010','李三'); -- 2:创建person表,表中的addr列引用了home_type对象类型 create table person( id number(6) primary key, name varchar2(10), addr ref home_type ); -- 插入数据,addr列将存入指向homes表相应数据的地址指针 insert into person select 1,'张三',ref(p) from homes p where p.owner='李四'; insert into person select 2,'张四',ref(p) from homes p where p.owner='李四'; insert into person select 3,'张五',ref(p) from homes p where p.owner='李四';
LOB变量是指用于存储大批量数据的变量。Oracle将LOB分为两种:内部LOB 和 外部LOB 。
内部lob包括
CLOB
、BLOB
、NCLOB
三种类型。它们的数据被存储在数据库中,并且支持事务操作(提交、回滚、保存点)。
CLOB
和NCLOB
:用于存储大批量字符数据。
BLOB
:用于存储大批量二进制数据。
BFILE
:存储指向操作系统文件的指针(地址)
PL/SQL有 分隔符、标识符、字面量、注释 等四种词汇单元
标识符可以用于定义变量、常量、异常、显式游标、游标变量、参数、子程序以及包的名称。
标识符使用规则:定义变量、常量时,每行只能定义一个标识符;不能使用Oracle关键字;标识符只能以A~Z,a~z开始,可以使用 A~Z,a~z,0~9,_,$,# ,最大长度为30个字符,如果要用其它字符或关键字,必须使用双引号包住
字面量指数字、字符、字符串、日期值、布尔值,而不是标识符。
数字字面量:100 2.45 3e3 5E6 6*10**3
字符字面量:'A' '9' '<' '' '%'
字符串字面量:'hello world' '$8888' '2003-01-13'
- 可以使用分隔符
[] {} <>
为字符串赋值:str_var:=q'[I'm a str]'
布尔字面量:true false null
日期时间字面量:'10-NVO-91' '2022-10-10 13:01:01'
分隔符是指具有特定含义的单个符号或组合符号。
单符号分隔符:
+, -, *, /
:加,减/负,乘,除%
:属性提示符'
:字符串分隔符.
:组件选择符(
)
:表达式或列表分隔符:
:非PL/SQL变量提示符,
:表,列名分隔符"
:标识符分隔符=
:相等操作符@
:远程访问指示符;
:语句终止符
组合分隔符:
:=
:赋值运算符=>
:关联操作符**
:幂运算符<<,>>
:标签分隔符(开始和结束)/*,*/
:多行注释分隔符(开始和结束)--
:单行注释提示符..
:范围操作符<, >, <=, >=
:关系运算符<>, '=, ~=, ^=
:不同版本的不相等操作符
注释用于解释单行或多行代码的作用,从而提高了PL/SQL程序的可读性。注释又分为单行注释和多行注释。
单行注释:-- 注释内容
多行注释:/* 注释内容 */
标识符命名规则:
- 定义变量时,建议使用 v_ 做为前缀
- 定义常量时,建议使用 c_ 做为前缀
- 定义游标时,使用 _cursor 作为后缀
- 定义异常时,使用 e_ 作为前缀
- 定义表类型时,使用 _table_type 作为后缀
- 定义表变量时,使用 _table 作为后缀
- 定义记录类型时,使用 _record_type 作为后缀
- 定义记录变量时,使用 _record 作为后缀
大小写规则:
- SQL关键字、PL/SQL关键字、数据类型采用大写格式
- 标识符、参数、数据库对象、列采用小写格式
代码缩进:
- 同级对齐,下级缩进一个tab
嵌套块和变量范围:
- 子块定义的标识符是局部标识符,主块定义的标识符是全局标识符
在PL/SQL块中可以使用的SQL函数:
- 当编写PL/SQL代码时,可以直接引用大多数的单行SQL函数。包括单行数字函数round 单行字符函数 upper 转换函数 to_char 日期函数 months_between,但是greatest、least、decode等等以及 所有分组函数 不能直接在PL/SQL语句中使用。