第13章 PL/SQL程序设计
内容提要 pl/sql过程化的语言进行程序设计的基础知识。
13.1 PL/SQL 基础知识 PL/SQL是过程化语言/sql的缩写,是Oracle在SQL的基础上扩展开发的一种数据库编程语言,在兼容标准SQL的基础上,扩充了许多新的功能,是面向过程化的语言与SQL语言的结合,特点如下:
(1) PL/SQL除了基本的SQL语句之外,还包括了控制结构和异常处理,从而具有SQL语言的简洁性和过程化的灵活性。 (2) 每个SQL语句的处理请求都将引起一次网络传输,容易导致网络拥塞。而PL/SQL是以整个语句块发给服务器的,从而减少了网络通信流量,提高了应用程序的执行速度。
(3)PL/SQL块可以被命名和存储在Oracle服务器中,同时也能被其他的PL/SQL程序或SQL语句调用,任何客户、服务器工具都能访问PL/SQL程序,具有很好的可重用性。
(4)通过授予用户执行PL/SQL块的权限,而不是直接授予用户对数据库对象的操作权限,提供了数据库的安全性。
(5) PL/SQL 是一种块结构语言,即构成一个PL/SQL程序的基本单位是块。
13.1.1 PL/SQL块 1.基本结构 PL/SQL程序的基本单位是块,块分匿名块、命名块两种。匿名块指未命名的块,只能执行一次,不能存储在数据库中。命名块指过程、函数、触发器和包等数据库对象,它们存储在数据库中,可以被多次调用执行。
匿名块的基本结构: [DECLARE] BEGIN [EXCEPTION] END;
说明 1. (1)DECLARE部分为声明部分,用来声明程序中用到的变量、类型和游标等,如果不需要声明,则这部分可以忽略。 (2)BEGIN部分是PL/SQL块的主程序体,一般使用SQL语句和过程性语句来完成和处理特定的工作。 (3)EXCEPTION异常处理部分也是可选的,用来检查和处理异常或错误。 (4)块中每一条语句都以分号结束。一条SQL语句可以分多行来写,但最终以分号结束。 (5)在PL/SQL程序块中,注释单行使用“一”表示,注释多行使用“/*……*/”形式。
2.块的执行 在SQL*Plus中,PL/SQL程序块通过在其后输入“/”来执行
【例13-1】PL/SQL程序块。 DECLARE name VARCHAR2(10):=‘wxh’; BEG工N DBMS_OUTPUT.PUT_L INE(name); END; / 【例13·2】PL/SQL程序块。 name CHAR(10)j Sex CHAR(2); BEGIN SELECT sname,SSex INTO name,sex FROM Stud WHERE sno=98001; __将检索的值存储到变量中 DBMS_OUTPUT.PUT_LINE(name); END; SQL>SET SERVEROUTPUT ON
13.1.2 声明常量、变量 1.声明常量 语句格式:<常量名> CONSTANT<数据类型>:=<值> ONSTANT选项表示声明的是固定不变的值,即常量。常用的数据类型如CHAR、 NUMBER、DATE、BOOLEAN等。常量一旦定义,在以后的使用中其值将不再改变。 2.声明变量 语句格式:<变量名><数据类型>NOT NULL【DEFAULT|:=默认值】 NOT NULL表示该变量非空,必须指定默认值,否则执行块时将返回出错信息。 DEFAULT和“:=”作用等同,可互相替换。 变量是存储值的内存区域,在PL/SQL中用来处理程序中的值。像其他高级语言程序一样,PL/SQL中的变量命名也要遵循一定约定,约定如下。 (1)变量名以字母开头,由字母、数字以及$、#或_组成,不区分大小写。 (2)变量名最大长度为30个字符。 (3)不能用系统保留字命名。 在PL/SQL中,每一行只能声明一个变量。
【例13.3】 声明常量、变量。 nl CONSTANTINT:=100: C CHAR(4); d DATE; n2 NUMBER(5)DEFAULT 100; name VARCHAR2(10):=’TOM’; istrue BOOLEAN DEFAULT TRUE;
3.绑定变量 绑定变量又称全局变量,用于将应用程序环境中的值传递给PL/SQL程序块中进行处 理。在SQL*Plus中创建绑定变量主要有CHAR、NUMBER和VARCHAR2类型,不存在 DATE和BOOLEAN数据类型的SQL*Plus变量。 在’SQL。Plus环境中声明绑定变量使用VAR关键字,在PL/SQL块内部使用该绑定变 量需在变量名前加冒号。
【例13-4】 输出所有雇员的平均工资。 SQL>SET SERVEROUTPUT ON SQL>VAR avgsal NUMBER; SQL>BEGIN . SELECT AVG(sal)INTO:avgsal FROM emp; _一只是将查询值赋给了avgsal,不会显示select语句的结果 DBMS_OUTPUT.PUT_LINE(:avgsal); END; { 2001.92308 PL/SQL过程已成功完成。 SQL>PRINT avgsal AVGSAL
为了减少程序的修改,方便操作数据表数据,还可以使用%TYPE和%RowTYPE两种类型来声明变量,使变量的类型与表中的保持一致。 在PL/SQL中,使用%TYPE声明的变量类型与数据库表中某字段的数据类型相同,如果表中的字段类型发生变化,则相应变量的类型也自动随之改变,用户就不必修改程序代码。
【例13.5】 输出7934雇员的姓名、岗位。 DECLARE . . my_name emp.ename%TYPE; 一声明%TYPE类型的变量 my_job emp.Joh%TYPE; BEG工N SELECT ename,Job INTO my_na~ne,my_job FROM emp WHERE empno=7934; DBMS—OuTPuT.PUT_LINE(my name l l。 ’l lmy_job); END; } M工LLER CLERK PL/SQL过程已成功完成。
【例13.6】 删除9988雇员。 BEGIN DELETE FROM emp WHERE empno=9988; COMMIT; END; / PL/SQL过程已成功完成。
5.%ROWTYPE类型 %ROWTYPE可以得到数据表中整条记录的数据类型。声明了%ROWTYPE类型的变量可以完整地存放数据表中的整条记录。
【例13.7】 输出7934雇员的姓名、岗位。 DECLARE empl emp%ROWTYPE; BEG工N SELECT‘INTO empl FROM emp WHERE empno=7934; DBMS_OUTPUT.PUT_LINE(empl.ename I I…’s Job is’I l empl.Job); END: | MILLER’s JOb iS CLERK PL/SQL过程己成功完成。
13.1.3 PL/SQL 流程控制 1.分支结构 PL/SQL分支结构有IF—THEN.ELSE语句和CASE语句两种。 语法为: IF条件表达式1 THEN 语句组1 [ELSIF条件表达式2 THEN 语句组2] [ELSE 语句组] END IF; 其中,ELSIF和ELSE子句是可选的,可以根据需要包含任意多个ELSIF子句,但ELSE 子句只能包含一个。
(2)CASE语句。 CASE WHEN表达式1 THEN语句组1 WHEN表达式2 THEN语句组2 WHEN表达式N一1 THEN语句组N一1 [ELSE语句组N] END CASE; CASE语句的功能为顺序检查表达式,一旦从中找到匹配的表达式值,就执行相应的 语句组并跳出CASE结构。ELSE子句是可选的。 以下通过实例来说明以上两种分支结构的应用。
【例13.8】 IF.THEN—ELSE结构。 DECLARE e_sal emp.sal%TYPE; BEGIN SELECT sal INTO e_sal FROM emp WHERE empno:7 9 3 4; IF e_sal<2000 THEN UPDATE emp SET comm=cOlitm+sal‘1.2 WHERE ELSIF e_sal>:2000 AND e_sal<2500 THEN UPDATE emp SET comm:coilqm+sal‘1.1 WHERE ELSE DBMS_OUTPUT.PUT—LINE(·不提高补助金·); END IF: END: empno:7934;
【例13.9】 CASE语句。 DE,CLARE e_deptno emp。deptno%TYPE歹 d_dname dept.dname%TYPE; e_ename emp.ename%TYPE 7 BEG工N SELECT deptno l ename INTO e_deptno l e_ename FROM emp WHERE empno=7 9 3 4; SELECT dname INTO d_dname FROM dept WHERE deptno=e_deptno; CASE WHEN d dname=。ACCOUNTING-THEN d_dname:=-财务部-歹 WHEN d_dname=。RE SEARCH’THEN d_dname:=’开发部,歹 WHEN d_dname=。SALES-THEN amdname:=t销售部·歹 WHEN amdname=’OPERATI ONS’THEN d_dname:=-项目部-歹 ELSE d_dname:=-没有这样的部门-; END CASE歹 DBMS_OUTPUT。PUT_L INE(d-dname); END歹 } j 财务部 PL/SQL过程已成功完成。
2。循环结构 ‘ PL/SQL的循环结构有简单循环、FOR循环和WHILE循环三种类型组成。 (1)简单循环。 语法: L00P 语句组 2。循环结构 ‘ PL/SQL的循环结构有简单循环、FOR循环和WHILE循环三种类型组成。 (1)简单循环。 语法: L00P 语句组 END LOOP; 这种循环结构是没有终止的,必须人为进行控制,一般通过加入EXIT或EXIT子句来结束循环。
(2)FOR循环。 FOR 循环变量 IN[REVERSE] 起始值..终止值LOOP 语句组 END LOOP; FOR循环的循环次数是固定的,如果使用了REVERSE选项,那么循环变量将从终止值到起始值降序取值。
(3)WHILE循环。 WHILE 条件表达式 LOOP 语句组 END LOOP; WHILE循环通过条件表达式来控制循环的执行,如果条件表达式为真(TRUE),则 执行循环体内的语句;如果为假(FALSE),则结束循环。
求“1+2+…+100”的值来说明三种类型循环的应用。 【例13-101 简单循环。 DECLARE V—Count 工NT:=1: V—sum 工NT:=0; BEG工N L00P V—sum:=V—sum+V—count; V—count:=v—count+1; EXIT WHEN v count>100; __结束循环 END LOOP: DBMS_OUTPUT.PUT_LINE(。1+2+…+100: END: | 1+2+…+100=5050 PL/SQL过程已成功完成。
【例13-III FOR循环。 DECLARE v_sum INT:=0; BEG工N FOR i IN 1..100 LOOP v sum:=v_sum+i; END LOOPj DBMS_OUTPUT.PUT_LINE(’1+2+…+100= END: { 1+2+…+100=5050 PL/SQL过程已成功完成。
【例13-121 WHILE循环。 DECLARE v_count NUMBER:=1 j v_sum NUMBER:=0j BEG工N WHILE v_count<=100 LOOP V—sum:=V~sum+V—count; END LOOP; DBMS_OUTPUT.PUT_LINE(’1+2+…+100: END; } 1+2+…+100=5050 PL/SQL过程已成功完成。 v_sum); v—sum)j
3.GOTO结构 GOTO语句可以将谭序控制转到设定的标签语句。标签的形式是‘‘<<>>”。格式 如下:
GOTO label—name j <<1abel—name>> 例如: DECLARE id NUMBER:=1: BEGIN L00P DBMS一OUTPU T.PUT_L工NE(‘循环次数—’|| id); id:=id+1; IF id=10’tHEN GOTO a: END工F: END LOOP; <<a>> :DBMS—OUq,PUqt.PUT—LINE(·跳出循环·); END;
13.2游 标 上一节中介绍了使用SELECT..INTO语句可处理表的单行数据,本节学习使用游标处理多行查询数据。Oracle把从数据表中查询出来的结果集存放在内存中,PL/sQL游标是指向该内存的指针,通过游标指针的移动实现对内存数据的各种操作处理,最后将操作结果写回到数据表中。 13.2.1处理游标 游标的处理包括4个步骤。 (1)声明游标。 (2)打开游标。 (3)将结果集中的数据提取(FETCH)到PL/SQL变量中。 (4)关闭游标。
1.声明游标 声明游标即定义游标的名称,并将该游标与一个SE[.ECT语句相关联。语法格式为: CURSOR游标名 IS SELECT语句; 其中,SELECT语句为游标所关联的查询语句。
2.打开游标 游标使用之前必须要打开,语法格式是: OPEN 游标名; 其中,游标名必须是一个已经被声明的游标。游标打开后,指针指向结果集的第一行。
3.提取数据 FETCH语句用来从游标中提取数据。在每次执行FETCH语句之后,游标指针都移向下一行。这样,连续的FETCH语句将返回SELEcT结果集中连续的行,直到整个结果集中的数据都被返回。语法格式为: FETCH游标名工NT0变量列表 注意,INTO子句中的变量列表用来存放游标中相应字段的数据,因此变量的个数、顺序、类型必须与SELECT查询中相应的字段列表相匹配。
4.关闭游标 当所有的结果集数据都被检索完以后,必须关闭游标,以释放游标所占用的资源。语法格式为: CLOSE 游标名; 一旦关闭了游标,再从游标中提取数据就是非法的,将会产生Oracle错误。
13.2.2 游标属性 在PL/SQL中可以使用游标的4个属性,%FOUND、%NOTFOUND、%ISOPEN和 %R0wC0uNT。游标属性返回的值为逻辑型值或数值,通过游标属性值可以获取游标 当前的状态,以此进行相应的控制和数据处理。关于游标4个属性的说明见表13—1。
游标的属性反映了游标的状态,下面假定stud表中只有两行记录,执行以下PL/SQL块: DECLARE CURSOR c—stud IS SELECT sname FROM stud; name stud.sname%TYPE: BEGIN --loc1 OPEN c_stud: --loc2 FETCH c—stud INTO name;
--loc3 FETCH c_stud INTO name; --loc4 --loc5 CLOSE c_stud; --loc6 END;
13.2.3 游标提取循环 1简单循环 例13-13 2 WHILE循环 例13-14 3FOR循环 简单循环和WHILE循环都需要使用OPEN、FETCH和CLOSE语句对游标进行显式地处理,FOR循环则可以隐式地进行游标处理,减少了语句书写。同样是上面的例子,使用FOR循环进行处理。 【例13.15]
13.2.4 参数化游标 如果游标相关联的SELECT语句中带有参数,则这种游标称为参数化游标。当打开这种类型的游标时,必须为游标参数提供数据。声明和打开游标的语法如下: 声明:CURSOR 游标名(参数声明) IS SELECT语句; 打开:OPEN游标名(参数值);
【例13.16】 使用参数化游标。
13.2.5 游标变量 以上定义的游标都与固定的一个查询语句相关联,可称为静态游标。下面要讲的游标变量是一种动态游标,可以在运行时刻与不同的查询语句相关联,极大地简化了处理。 1.声明游标变量 游标变量可以使用的类型是REF CuRSOR,定义一个游标变量类型的语法为: TYPE类型名 IS REF CURSOR[RETURN返回类型] ; 其中,类型名是新建游标类型的名称;返回类型是一个记录类型,它指明了最终由游标变量返回的选择列表的类型,为可选子句。 定义了REF CURSOR游标类型后,就可以声明游标变量了,语法格式如下: 游标名 游标变量类型;
2.打开并使用游标变量 如果要将一个游标变量与一个特定的SEI.,ECT查询相关联,使用OPEN的如下语法格式: OPEN游标变量FOR SE[.EcT语句; 其中,游标变量是一个已经被定义的游标变量,SEI.,ECT。语句为该游标变量当前相关联的查询语句。游标变量与一个SElECq、语句相关联打开后,就可以使用FETCH语句从结果集中提取数据并进行相应的处理,与静态游标相同可以使用游标循环。 当使用OPEN…FOR语句打开一个查询语句时,游标变量上一个相关联的查询语句将会被覆盖。 3.关闭游标变量 游标变量的关闭和静态游标的关闭类似,都是用C【.OSE语句,以释放游标所占用的资源。 语法格式为:CLOSE 游标变量名;
例13-17 提取游标变量操作示例。
13.3过程和函数 前面所讲的PL/SQL块都是匿名块,每次执行时都要进行编译,而且匿名块不存储在数据库中,不能被SQL或其他PL/SQL程序调用。后面几节中我们将介绍过程、函数、包、触发器四种命名块,这些命名块创建成功后,首先被编译,然后作为Oracle数据库对象以被编译的形式存储在数据库中,其他应用程序可以按名称多次调用执行,连接到Oracle数据库的用户只要有合适的权限都可以使用。本节先介绍过程和函数。
过程和函数的结构是相似的,一般都被称为子程序(SUBPROGRAM),它们都可以接收输入值并向应用程序返回值。但两者也存在一定的区别,过程用来完成特定的功能,可能不返回任何值,也可能返回多个值,过程的调用本身就是一条PL/SQL语句,不能作为表达式的一部分;函数包含RETURN子句,用来进行数据操作,并返回一个函数值,函数的调用只能在一个表达式中。
13.3.1过程基本操作 过程的基本操作有创建过程、查看过程、修改过程、调用过程和删除过程。
1.创建过程 语法如下: CREATE[OR REPLACE]PROCEDURE过程名 [参数1 {IN | OUT | IN OUT)类型, 参数2{IN I OUT l IN OUT}类型, 参数N{IN|OUT|IN OUT}类型] {IS | AS } 过程体
说明: (1) OR REPLACE关键字可选,但一般会使用,功能为如果同名的过程已存在,则删除同名过程,然后重建,以此来实现修改过程的目的。 (2)过程可以包含多个参数,参数模式有IN、OUT和IN OUT 三种,默认为IN,过程也可以没有参数。
(3)IS和AS关键字等价 (4)过程体为该过程的代码部分,是一个含有声明部分、执行部分和异常处理部分的PL/SQL块。但需要注意的是,在过程体的声明中不能使用DECLARE关键字,由IS或AS来代替。
2 查看过程 过程创建成功后,即说明编译已经成功,并把它作为一个Oracle对象存储在数据库中,使用user_source视图查看过程的源程序代码信息,使用user_objects视图可以查询到该数据库对象。 Sql>desc user_source Sql>select text FROM user_source WHERE name=‘VIEW_STU’;
Desc view_stu;
(1)在SQL*Plus中直接用EXECUTE命令调用: SQL>EXECUTE proc_name(parl,par2…); (2)PL/SQL程序块调用: BEGIN proc_name(parl,par2…); END;
4.删除过程 删除过程的语法如下: DROP PROCEDURE 过程名;
下面是一个完整的创建、查看、调用过程的一个实例。 【例13.18 完成以下操作。 (1)编写过程,显示指定雇员所在的部门名称和所在城市。 SQL>CONN scott/tiger SQL>CREATE OR REPLACE PROCEDURE deptmesg(p_ename emp.ename%TYPE) AS p_dname dept.dname%TYPE; p_loc dept.loc%TYPE; BEG工N SELECT dname,loc INTO p.dname,p_loc FROM emp.dept WHERE emp.deptno=dept.deptno AND emp.ename=p.ename; DBMS_OUTPUT.PUT_LINE(p_dname||’ ’|| ploc); END; } 过程已创建。
(2)查看以上过程。User_objects和user_sourece sQL>SELECT obj ect_name FROM user_obj ects WHERE obj ect_type=’PROCEDURE’; OBJECT_NAME DEPTMESG SQL>SELECT text FROM user_source WHERE name=’DEPTMESG’; TEXT PROCEDURE deptmesg(p_ename emp.ename%TYPE)AS p_dname dept.dname%TYPE; p_loc dept.10c%TYPE; BEG工N SELECT dname.10c INTO p_dname,p_loc FROM emp l dept WHERE emp.dep七no:dep七.deptno AND emp.ename=p_ename; DBMS_OUTPUT.PUT—LINE(p_dname I I’ ’J l p_loc); END;
(3)调用以上过程。 在PL/SQL程序中调用: BEGIN DeptMesg('SMITH'); END; / RESEARCH DALLAS PL/SQL过程已成功完成。
13.3.2参数和模式 DeptMESG过程,并且可以在以下的PL/SQL块中调用它: DECLARE e_name emp.ename%TYPE:='SMITH'; BEGIN DeptMESG(e_name); END; 在上面块中声明的变量e_name作为参数传递给DEPTMESG,称为实际参数。DEPTMESG过程中的p_ename就是形式参数。实际参数包含了在调用时传递给该过程的数值,同时它们也会接收在返回时过程的处理结果。形式参数只是实际参数取值的占位符,在过程被调用时,形式参数被赋予实际参数的取值。当过程返回时,实际参数被赋予形式参数的取值。
参数模式决定了形参的行为,PL/SQL中参数模式有IN、OUT和IN OUT三种,默认为IN。
【例13-191 使用不同参数模式的示例。 CREATE OR REPLACE PROCEDURE proce_test(p_in IN VARCHAR2,P_out OUT VARCHAR2,p_inout IN OUT VARCHAR2) AS varl VARCHAR2(20); BEGIN
varl:=p_in; p_out:=varl | Ip_inout; END; { 过程已创建。
调用以上过程,体会参数的三种模式。 SUL>DECLARE v_out VARCHAR2; v_inout VARCHAR2; BEGIN v_inout:=‘ff’; proce_test(’dd’,v_out,v_inout); DBMS_OUTPUT.PUT_LINE(v_out); END; } ddff PL/SQL过程已成功完成。
另外,可以为参数定义默认值,语法如下: 参数名 参数类型{[DEFAULT ]:=]}默认值。 调用过程时,如果没有给参数赋值,则使用默认值。
13.3.3函数基本操作 函数的基本操作包括创建函数、查看函数、修改函数、调用函数及删除函数等。 1.创建函数 创建函数的语法如下: CREATE[OR REPLACE]FUNCTION函数名 [参数1{IN I OUT I IN OUT)类型, 参数2(IN l OUT l IN OUT}类型, 参数N(IN I OUT l IN OUT}类型] RETURN返回类型 (IS l AS) 函数体 其中,RETURN指定了该函数返回的数值的类型,是必选项,因为调用函数是作为表达式的一部分。函数体是一个含有声明部分、执行部分和异常处理部分的PL/SQL块。 查看函数和修改函数均和过程的操作类似,不再详细讲述。
2.调用函数 函数创建成功后,就可以在任何一个PL/SQL程序块中调用,但不能在SQL*Plus中使 用EXECUTE命令来调用,因为函数是有返回值的,必须作为表达式的一部分来调用。 3.删除函数 删除函数的语法如下: DROP FUNCTION 函数名;
下面是一个完整的创建、调用函数的一个实例。 【例13.20] 完成以下操作。 (1)编写一个函数以显示该雇员在此组织中的工作天数。 CREATE OR REPLACE FUNCTION hire_day(no emp.empno%TYPE) RETURN NUMBER AS vhiredate emp.hiredate%TYPE; vday NUMBER; BEG工N SELECT hiredate INTO vhiredate FROM emp WHERE empno=no; vday:=CEIL(SYSDATE—vhiredate); 一CEIL返回最小整数值 RETURN vday; END: { 函数已创建。
(2)调用以上函数。 DECLARE nl number; BEGIN nl:=hire_day(7900); DBMS_OUTPUT.PUT_LINE(nll I‘days。); END: / 9866 days PL/SQL过程已成功完成。
13.4包 包是继过程和函数之后的第三种类型的命名PL/SQL块,它是将类型、变量、过函数和游标等相关对象存储在一起的一种PL/SQL结构。包的使用有效隐藏了对象信同时也有利于PL/SQL程序的维护。 包由包头和包体两部分组成,包头和包体都单独被存储在不同的数据字典中。包含了有关包的内容信息,但不包括任何代码。包头对于一个包来说是必不可少的,而有时则不一定是必需的。包中所包含的过程、函数、游标和变量必须在包头中声明,它们的实现代码则包含在包体中。如果包头编译不成功,则包体编译必定不成功。只有和包体都编译成功,包才能使用。
1.创建包头 创建包头的语法格式如下: CREATE [OR REPLACE]PACKAGE包名 <IS |AS) 类型l变量l游标l异常l函数|过程声明 END[包名]; 需要说明的是,如果包头不包含任何过程和函数,仅包含变量声明、游标、类型等,那么包体可以没有,这种技术对于声明全局变量是很有用的,包中所有的对象在包的外面都是可见的。
创建包体使用CREATE PACKAGE BODY语句,包体中可以声明自身的私有变量、游标、类型、过程、函数等。 1.查看包 包创建成功后,可以在USER_OBJECTS视图中查看包信息,在USER_SOURCE视图中查看包的源代码。 2.调用包中的对象 过程、函数、触发器及PL/SQL程序块等,可以通过在包名后添加“.”来调用包内的类型、子程序等对象。
3.修改包 修改包,只能通过带有OR REPLACE选项的CREATE PACKAGE语句重建。重建的包将取代原来包中的内容,达到修改包的目的。 4.删除包 删除包时将包头和包体一块删除,其语法如下: DROP PACKAGE包名;
以下是创建、查看、调用包的一个实例。 【例13.21] 使用学生一选课数据库的表stud。 (1)创建包。 . /*包头*/ CREATE OR REPLACE PACKAGE stu_package AS PROCEDURE addstud(p_sno stud.sno%TYPE, p_sname stud.sname%TYPE, p_sSex stud.ssex%TYPE, p_sage stud.sage%TYPE, p_sdept stud.sdept%TYPE); PROCEDURE removestud(p_sno stud.sno%TYPE)j FUNCTION get_name(p_sno stud.sno%TYPE)RETURN VARCHAR2; END; / 程序包已创建。
/*包体*/ CREATE OR REPLACE PACKAGE BODY stu__package AS PROCEDURe addstud(p_sno stud.sno%TYPE, 一给表添加记录的过程 p_sname s tud.sname%TYPE, p_ssex stud.ssex%TYPE, p_sage stud.sage%TYPE, p_sdept stud.sdept%TYPE) IS BEG工N INSERT INTO stud VALUES(p_sno,p_sname,p_s sex,p_sage,p_dept); COMMIT; END addstud;
PROCEDURE removestud(p_sno stud.sno%type)IS 一按学号删除学生记录的过程 BEG工N DELETE FROM stud WHERE sno=p_sno; COMMIT; END removestud; . FUNCTION get_name(p_sno stud.sno%type)RETURN VARCHAR2 一一按学号查询学生姓名的函数 AS name stud.sname%TYPE; SELECT sname INTO name FROM stud WHERE sno:p_sno; RETURN name; END get_name; END stu_package£ } 程序包主体已创建。
(2)查看以上包的信息。 sQL>sELEcT obj ect_name FROM user_obj ects WHERE obj ect_type=’PACKAGE’; OBJECT—NAME STU—PACKAGE SQL>SELECT text FROM user_source WHERE name=’STU—PACKAGE’; 将显示包头、包体的源代码。
(3)调用包。 SQL>EXECUTE stu_package.addstud(·23458t,·王晓t,·女·,20,-计算机-); PL/SQL过程已成功完成。 SQL>DECLARE strl VARCHAR(30); BEG工N strl:=stu_package.get_name(‘23458’); DBMS_OUTPUT.PUT_LINE(。23458:’l I’ ’I l strl); END: / 23458:王晓
13.5触 发 器 触发器类似于过程和函数,也是具有声明部分、执行部分和异常处理部分的命名块,作为Oracle对象存储在数据库中。但触发器是一种特殊类型的PL/sQL程序块,当触发事件发生时被触发执行,并且触发器不能接受参数。执行触发器的操作就是“点火(FIRING)”触发器。 使用触发器可以实现许多功能,如可以用来维护数据的完整性,当表被修改的时候,可以自动给其他需要执行的程序发出信号等。
13.5.1创建触发器 下面通过一个实例体会触发器的作用及点火的过程。 【例13.22] 创建触发器。 【例13.22] 创建触发器。 CREATE 0R REPLACE TRIGGER stud_count AFTER DELETE ON stud DECLARE v_count INTEGER; BEG工N SELECT COUNT(‘)INTO v_count FROM stud; DBMs—OuTpuT.PUT_LINE(。Student table now have,ll v_count ll’student.’); END; | 触发器已创建。
上面代码创建的触发器当在STUD表中删除记录后,显示表中还有几条记录的信息。 再执行下面的代码,可以看到触发器已被触发。 SQL>DELETE FROM Stud WHERE sno=23456; Student table now have 5 student. 已删除1行。
13.5.3 触发器基本操作 1.查看触发器 触发器作为对象存放在数据库,与触发器有关的数据字典有user_triggers、all—triggers和dba_triggers等,其中,user_triggers存放当前用户的所有触发器,all_triggers存放当前 用户可以访问的触发器,dba_triggers存放数据库中所有触发器。 2.修改触发器 修改触发器通过带有OR REPLACE选项的CREATE TRIGGER语句重建。而ALTERTRIGGER语句则用来生效或禁止触发器。 3.改变触发器的状态 触发器有ENABLED(允许点火)和DISABLED(禁止点火)两种状态。禁止触发器指禁止点火触发器,并不是删除它。新建的触发器默认是ENABLED状态。改变触发器的状态使用ALTER TRIGGER语句。语法格式为: alter trigger 触发器名 ENABLED|DISABLED;
如果使一个表相关的所有触发器都允许