Oracle定义PL/SQL变量

 

前言:
使用变量可以保存计算机需要处理的数据,为了给该变量分配适当的内存空间,还需要指定数据类型,有的数据类型还需要指定长度,如字符串。
有些类型可以用于建表(如char),有些则不能(如boolean,rowtype)。
同样是字符串,建表时的限制为4000,在脚本中则为3万多。

简单语法:变量名 数据类型;
完整语法:变量名 [constant] 变量类型 [not null] [default 值 | :=值]

其中“[ ]”表示可以不写,“|”表示任选其一。

下面给出变量定义及解释,数据类型先用建表时所用的数据类型:v1 char:
说明:没有给出长度,所以v1只能保存一个字符。超过了则会出错:数字或值错误 : 字符串缓冲区太小。

v2 varchar2(10);
说明:v2最多只能保存10个字符。如果不写长度,会出错:字符串长度限制在范围(1...32767)

v3 number;
说明:v3保存的数字范围非常大,几乎可以认为是没有限制的。

v4 number(5);
说明:v4最多能够保存5位整数。如果有小数,Oracle会自动四舍五入。如果整数部分超过5位,则会报错:数字或值错误 : 数值精度太高。

v5 number(5,2);
说明:v5最多能够保存3位整数,2位小数。如果小数位不止2位,则Oracle会自动四舍五入。整数位超过3位会报错,同上。

v6 date;
说明:可以直接保存sysdate的值;如果是指定日期,则要用to_date来转化。否则报错:文字与格式字符串不匹配。

定义了变量,变量的默认值为空,此时进行计算,结果一定为NULL。所以变量必须初始化。
初始化有三种方式:

v7 constant number := 100;
说明:定义v7为常量,定义时就必须给定值。然后在程序中就不能再对v7进行赋值了,否则会报错:表达式 'V7' 不能用作赋值目标。

v8 number default 10;
说明:定义v8时就给定默认值10。注意,number类型变量的默认值不是0,而是NULL。

v9 number not null := 1000.50;
说明:定义v9变量不能为空,此时必须给出一个不为NULL的值。在运行时发现v9为NULL,则报错:说明为 NOT NULL 的变量必须有初始化赋值。

预测各打印结果,如果代码有错误请先改正:

declare 
v1 char;
v2 varchar2(10);
v3 number;
v4 number(5);
v5 number(5,2);
v6 date;
v7 number default 10;
begin 
v1:='ab'; 
v2:='abcd';
v4:=9998.99;
v5:=1000.5555555;
v6:=to_date('2002-10-2','yyyy-mm-dd');
dbms_output.put_line(v1);
dbms_output.put_line(v2);
dbms_output.put_line(v3+100);
dbms_output.put_line(v4);
dbms_output.put_line(v5);
dbms_output.put_line(v6);
dbms_output.put_line(v7+100);
end;

只能在脚本中使用的变量类型:
上面的数据类型,同时在建表时也能使用。而下面的数据类型只能在PL/SQL脚本中使用。
即:boolean,type,rowtype,record,替代变量、table类型。
其中:
·一个变量只能保存一个值,叫做“标量变量”。如:char、type。
·一个变量只能保存多个值,叫做“复合变量”。如:rowtype、record,table。

1、布尔类型 boolean
boolean类型主要表达真或假。可以为boolean类型变量赋值true或false。
主要用于PL/SQL脚本的流程控制。

示例:

declare 
v1 boolean;
begin 
v1:=1>2;
dbms_output.put_line(v1);
end;

问题:打印的结果是什么,是true、false、1、0?
回答:
都不对。运行时得到错误信息:调用 'PUT_LINE' 时参数个数或类型错误。
这是因为在脚本中不能直接打印boolean类型的值,所以只能在脚本中使用if语句来判断。

修改示例:

declare 
v1 boolean;
begin 
v1:=1>2;
if(v1)then 
     dbms_output.put_line('真');
else 
    dbms_output.put_line('假');
end if;
end;


打印:

2、type类型。
语法:表.字段%TYPE
返回:某个表的字段的实际类型。
作用:
PL/SQL脚本中,有时定义的变量就是存取表中数据的。此时数据类型及长度就需要与字段的定义一致。可以去查看该字段的具体类型,但这样做很麻烦;并且当字段定义改变时,脚本也需要修改。
所以使用type类型来引用该字段的类型,更方便,维护性更好。

示例:根据工号查询员工姓名。
分析:要从emp表中获取姓名,必须要用查询语句。而要从查询语句中获取返回的值,要加上“into 变量”。

declare
    v_empno emp.empno%type;
    v_ename emp.ename%type;
begin
    v_empno:=7900;
    select ename into v_ename from emp where empno=7900;
    dbms_output.put_line(v_ename);
end;

3、rowtype类型
语法: 表%rowtype
作用: 保存了某一行记录的所有字段的值。

示例:根据工号为7900的员工的以下信息:ename,job,sal,comm,hiredate。
第一种:如果用type类型,定义5个变量保存查询结果。代码略。
第二种:如果用rowtype类型,只需要定义一个rowtype类型的变量。

代码:

declare
    v_empno emp.empno%type;
    v_row emp%rowtype;
begin
    v_empno:=7900;
    select * into v_row from emp where empno=7900;
    dbms_output.put_line('ename='||v_row.ename);
    dbms_output.put_line('job='||v_row.job);
    dbms_output.put_line('sal='||v_row.sal);    
    dbms_output.put_line('comm='||v_row.comm);
    dbms_output.put_line('hiredate='||v_row.hiredate);    
end;


打印:
ename=JAMES
job=CLERK
sal=950
comm=
hiredate=03-12月-81

说明
·必须select *,或者根据表结构的顺序写出所有字段名。
·使用rowtype类型最主要的限制在于表中不能有大对象字段如:CLOB、BLOB。

4、record类型
record的意思是“记录”。
有时,用type类型会定义太多的变量,用rowtype又会取到自己不关心的数据。
如何只取自己关心的字段的值呢?此时就用record类型来自定义有多少个列。
语法:

type 类型名 is record(
   属性名1 属性类型,
   属性名2 属性类型
);


注意
1、属性之间定义用的是逗号(,),不是分号(;)。
2、最后一个属性名不需要再用“,”。

使用步骤有两个:
1、先用type自定义一个新的类型,这个类型的变量能够的变量与定义有关。
2、再用这个新的类型来定义一个变量,这个变量才能保存实际的数据。

示例:需求同上。

declare
--自定义一个类型
type myType is record(
    xm emp.ename%type, --姓名
    gzuo emp.job%type, --工作
    gzi emp.sal%type --工资
);
--使用自定义类型来定义变量
myValue myType;
begin
    select ename,job,sal into myValue from emp where empno=7844;
    dbms_output.put_line('ename='||myValue.xm);
    dbms_output.put_line('job='||myValue.gzuo);
    dbms_output.put_line('sal='||myValue.gzi);
end;



说明:
· 在查询时必须与自定义类型的属性顺序一一对应。
·myValue中的属性名也是自定义的,不是字段名。

问题:上面的代码比直接用type类型还多些,看不出优势在什么地方。为什么还要用record?
回答:
在项目中,自定义类型通常会放到在包(package,后面会专门学习)中,这样就可以在其它地方直接引用了。

示例:
先在包中自定义类型:

create or replace package my_bao
as
type myType is record(
    xm emp.ename%type, --姓名
    gzuo emp.job%type, --工作
    gzi emp.sal%type --工资
);
end;


然后就可以在块中直接使用该类型,只不过在类型前要加上包名:“my_bao”。
declare
--使用包中自定义类型来定义变量

myValue my_bao.myType;
begin
    select ename,job,sal into myValue from emp where empno=7844;
    dbms_output.put_line('ename='||myValue.xm);
    dbms_output.put_line('job='||myValue.gzuo);
    dbms_output.put_line('sal='||myValue.gzi);
end;