变量的作用域: 变量可以使用的程序单元部分
可见性: 当一个变量在它的作用域中可以用一个不限定的名字来引用时
1.CONSTANT 声明一个常量
2.NOT NULL 约束变量不能为空
3.:=value 用于为变量附初始值
例如
v_name DATE NOT NULL := SYSDATE
v_name INT NOT NULL DEFAULT 7369
变量在没有被初始化的时候 变量会被初始化成null值 即使+1 依然还是null值
%TYPE
例子 用于定义相同类型的变量 用于绑定单个列的值
v_empno emp.empno%TYPE
%ROETYPE
用于绑定一整行的 所有列
v_emp emp%ROWTYPE
%TYPE 和 %ROWTYPE 只提供类型信息 并不能保证NOT NULL 约束
本地变量:在PLSQL块或子程序中定义的变量仅在本地可用,如果在块之外访问变量是非法的,这种变量称为本地变量 当超出其作用域时,变量使用的内存将会被释放,直到变量被重新定义并初始化
外部块中定义的变量对于子块来说是全局的,如果全局变量在子块中又被重新声明,那么全局变量和本地声明的变量在子块的作用域是存在的,要访问外部块的全局变量,需要使用限定修饰符。
当外部块和内部快都同时声明同一变量 优先访问本地的
12-8-5
<<outer>>
declare
v_empname varchar2(20);
begin
v_empname:='张三';
<<inner>>
declare
v_empname varchar2(20);
begin
v_empname:='李四';
dbms_output.put_line('内层块的员工名称:' || v_empname );
dbms_output.put_line('外层块的员工名称:' || outer.v_empname);
end;
dbms_output.put_line('outer员工名称:' || v_empname);
end;
12-9-1
数据类型
PLSQL 是一种静态类型化的程序设计语言,静态类型化又称为强类型化,也就是说类型会在编译时被检查,而不是在运行时,增强程序的稳定性
标量类型:用来保存单个值的数据类型,包含字符型,数字型,布尔型和日期型
复合类型:记录 嵌套表 索引表和变长数组
引用类型:REF CURSOR 和REF 2种
LOB类型:用来处理二进制和大于4GB的字符串
每个oracle数据库表都有一个名为ROWID的伪列。
SQL> select rowidtochar(rowid),ename,empno from emp;
ROWIDTOCHAR(ROWID) ENAME EMPNO
------------------ ---------- ----------
AAAQ+jAAEAAAAAeAAA SMITH 7369
AAAQ+jAAEAAAAAeAAB ALLEN 7499
AAAQ+jAAEAAAAAeAAC WARD 7521
AAAQ+jAAEAAAAAeAAD JONES 7566
AAAQ+jAAEAAAAAeAAE MARTIN 7654
AAAQ+jAAEAAAAAeAAF BLAKE 7698
ROWID:物理ROWID和逻辑ROWID
物理:标识普通数据表中的一行信息 逻辑:能够标识索引组织表中的一行信息
UROWID 可以存储 物理 逻辑 以及非 oracle 的ROWID
ROWID 可以显著的加速数据检索的性能。只要行存在 物理ROWID 值就不会改变。
declare
v_empname ROWID;
v_othersname VARCHAR(18);
begin
select ROWID into v_empname from emp where empno=&empno;
dbms_output.put_line(v_empname);
v_othersname:=ROWIDTOCHAR(v_empname);
dbms_output.put_line(v_othersname);
end;
数字类型 NUMBER:精度:所允许的的总长度 刻度:小数点右边多少位 如果为负值 及小数点左边多少位
指定刻度超过 四舍五入
v_num NUMBER(4,-1):=31451 41450
v_num NUMBER(4.3):= 3.1415926 3.142
用来存储符号整型值 PLS_INTEGER BINARY_INTEGER
PLS_INTEGER 相对于NUMBER 来说需要更少的内存 来存储数据而且在计算方面比NUMBER更有效率
NUMBER数据类型是以十进制格式进行存储的 为了进行数学运算 需要转换成二进制 所以速度会慢。
PLS_INTEGER 和 BINARY_INTEGER 都是以2的补码格式进行计算的 PLS_INTEGER 在溢出时会触发异常报错 而 BINARY_INTEGER 会转换成NUMBER 不会报错。
SQL> select sessiontimezone from dual;
SESSIONTIMEZONE
---------------------------------------
+08:00
获得当前时区
12-9-2
INTERVAL 类型
INTERVAL YEAR TO MONTH 用来存储和操纵年和月之间的时间间隔
INTERVAL DAY TO SECOND 用来存储和操纵天数,小时,分钟和秒之间的时间间隔。
declare
v_start timestamp;
v_end timestamp;
v_interval interval year to month;
v_year number;
v_month number;
begin
v_start := TO_TIMESTAMP('2010-05-12','YYYY-MM-dd');
v_end := CURRENT_TIMESTAMP;
v_interval := (v_end - v_start) YEAR TO MONTH;
v_year := EXTRACT(YEAR FROM v_interval);
v_month := EXTRACT(MONTH FROM v_interval);
dbms_output.put_line('当前的interval值为:' || v_interval);
dbms_output.put_line('INTERVAL年份为:' || v_year || CHR(13)||CHR(10)|| 'INTERVAL月份为:'|| v_month );
v_interval := INTERVAL '01-03' YEAR TO MONTH;
dbms_output.put_line('当前INTERVAL值为:' || v_interval);
v_interval := INTERVAL '01' YEAR;
dbms_output.put_line('当前的INTERVAL值为:' || v_interval);
v_year := EXTRACT(YEAR FROM v_interval);
v_month := EXTRACT(MONTH FROM v_interval);
dbms_output.put_line('INTERVAL年份为' || v_year || CHR(13)|| CHR(10)||'INTERVAL月份为:'|| v_month );
v_interval := INTERVAL '03' MONTH;
dbms_output.put_line('当前的INTERVAL的值为:' || v_interval);
end;
结果:
当前的interval值为:+04-07
INTERVAL年份为:4
INTERVAL月份为:7
当前INTERVAL值为:+01-03
当前的INTERVAL值为:+01-00
INTERVAL年份为1
INTERVAL月份为:0
当前的INTERVAL的值为:+00-03
引用类型
1.REF CURSOR 类型的变量通常称为游标变量
create or replace function selectallemployments
return sys_refcursor
as
st_cursor sys_refcursor;
begin
open st_cursor for select * from emp;
return st_cursor;
end;
declare
x sys_refcursor;
v_emp emp%ROWTYPE;
begin
x := selectallemployments;
loop
fetch x
into v_emp;
exit when x%NOTFOUND;
dbms_output.put_line('员工编号:' || v_emp.empno || '员工名称:' || v_emp.ename);
end loop;
end;
用户自定义类型
引用游标使用示例
declare
subtype empcounttype is integer;
empcount empcounttype;
begin
select count(*) into empcount from emp;
dbms_output.put_line('员工人数为:' || empcount);
end;
使用%TYPE
declare
TYPE empnamelist is table of varchar2(20);
subtype namelist is empnamelist;
type emprec is record(
empno number(4),
ename varchar2(20)
);
subtype emprecord is emprec;
subtype empno is emp.empno%TYPE;
subtype emprow is emp%ROWTYPE;
begin
null;
end;
子类型具有的优势:
1.可以检查数值是否越界,这样可以提高应用程序的可靠性。例如如果想要让某个数字类型在0~9这个范围之间,可以基于NUMBER类型定义一个子类型,这样在赋值时,如果数据溢出,编译器会弹出错误提示
declare
subtype numtype is number(1,0);
x_value numtype;
y_value numtype;
begin
x_value := 3;
y_value := 10; 因为10 报错 精度太高
end;
2.未约束的子类型可以和它的基本类型交互使用
declare
subtype numtype is number;
x_value number;
y_value numtype;
begin
x_value:= 10;
y_value := x_value;
end;
3.如果基类相同 那么子类型可以交互使用
declare
subtype numtype is varchar2(200);
x_value varchar2(20);
y_value numtype;
begin
x_value:='This is a word';
y_value:=x_value;
end;
12-10 数据类型转换
显示转换
declare
v_startdate DATE;
v_enddate DATE;
v_resultdate NUMBER;
begin
v_startdate:=TO_DATE('2007-10-11','yyyy-MM-dd');
v_enddate:=TRUNC(SYSDATE);
v_resultdate:=v_enddate-v_startdate;
dbms_output.put_line('起始日期:'
|| TO_CHAR(v_startdate,'yyyy-MM-dd')
|| CHR(13)
||CHR(10)
||'结束日期:'
||TO_CHAR(v_enddate,'yyyy-MM-dd')
||CHR(13)
||CHR(10)
||'相差天数:'
||TO_CHAR(v_resultdate));
end;
隐示转换
declare
v_startdate char(10);
v_enddate char(10);
v_result NUMBER(5);
begin
select min(hiredate) into v_startdate from emp;
select trunc(sysdate) into v_enddate from dual;
dbms_output.put_line('起始日期:'
|| v_startdate
|| CHR(13)
|| CHR(10)
|| '结束日期:'
|| v_enddate );
v_startdate:='200';
v_enddate:='400';
v_result:=v_enddate-v_startdate;
end;
表达式
declare
v_sal NUMBER;
v_result NUMBER;
begin
select sal into v_sal from emp where empno=&empno;
v_result:=v_sal * (1+0.15);
end;
运算符类型
赋值运算符,连接运算符,逻辑运算符,比较运算符。
PLSQL中一个左值仅能有一个右值 val1:=val2:=val3:=val4=0 这样是错误的
连接运算符
declare
x varchar2(8):='你好';
y varchar2(8):='中国';
z varchar2(10);
begin
dbms_output.put_line(x || z || NULL || y);
end;
执行结果 因为z没有赋值 所以是一个null 连接一个null 2个就都不显示
SQL> declare
2 x varchar2(8):='你好';
3 y varchar2(8):='中国';
4 z varchar2(10);
5 begin
6 dbms_output.put_line(x || z || NULL || y);
7 end;
8 /
你好中国
PL/SQL 过程已成功完成。