PL/SQL数据库开发那点事

PL/SQL数据库开发那点事-->编程,存储程序

在SQL*plus 中编写PL/SQL程序,并在SQL*plus 中执行它, PL/SQL块的代码就存放在SQL*plus的缓冲区中。
若是在SQL*plus 中执行了其余的SQL语句或PL/SQL块,缓冲区中就会存放新的代码,原来的PL/SQL块就会被从缓冲区中清除出去。
这种没有名称只是临时存放在缓冲区中的PL/SQL块叫作匿名块。
匿名块就是没有名字的PL/SQL块,它仅存放在缓冲区中,只能在当前SQL*plus环境中执行。
若是但愿PL/SQL块能随时被调用执行,而且能被数据库用户共享,就须要建立存储程序
存储程序是有名字的PL/SQL块,用户能够根据它的名字进行屡次调用。sql

存储程序在建立时通过了编译优化,被存放在数据库中,任何用户只要有适当的权限,就能够调用它。
并且在调用时无需再进行编译,所以能以很快的速度执行。
与匿名块相比,存储程序是做为数据库对象存储在数据库中的,所以,首先要在数据库中建立存储程序。数据库

存储程序的调用能够在SQL语句中、应用程序中、SQL*plus 中以及其余PL/SQL块中进行。
在第一次被调用时,存储程序的代码被装载到系统全局区的共享池中,之后再次调用时直接从共享池中取出代码便可执行。
存储程序与前面介绍的子程序的区别在于子程序是完成某个特定功能的程序段,它自己并不能单烛执行,只能做为一个模块,在一个PL/SQL块内部被调用执行。
而存储程序是一个可单独执行的程序,它能够包含多个子程序,能够在SQL语句中、应用程序中、SQL*plus 中以及其余PL/SQL块中被调用执行。
存储程序的形式包括:存储过程、存储函数、触发器和程序包等。编程

存储过程安全

若是用户要在本身的模式中建立存储过程,须要具备CREATE PROCEDURE系统权限,若是要在其余用户的模式中建立存储过程,则须要具备CREATE ANY PROCEDURE 系统权限
建立存储过程的语法为:oracle

CREATE OR REPLACE PROCEDURE 过程名(参数1,参数2 ...)ide

AUTHID CURRENT_USER | DEFINER函数

ASoop

  声明部分post

BEGIN优化

  可执行部分

EXCEPTION

  异常处理部分

END;

其中OR REPLACE选项的做用是当同名的存储过程存在时,首先将其删除,再建立新的存储过程。
固然,条件是当前用户具备删除原存储过程的权限。

存储过程在建立过程当中已经进行了编译和优化。
若是须要对存储过程进行修改,不能直接修改它的源代码,只能执行CREATE命令从新建立。
存储过程、存储函数、程序包都是这样的状况。
存储过程能够带有参数,这样在调用存储过程时就须要指定相应的实际参数。

若是没有参数,过程名后面的圆括号和参数列表就能够省略了。
每一个参数的定义格式为:

参数名 参数传递模式 数据类型 := 默认值

参数各定义中各部分的用法与子程序中的参数彻底相同。

AUTHID 选项用来规定存储过程执行时的权限。

这个选项有两个可选值,即CURRENT_USERDEFINER ,两者只能选择其中一个。
过程的执行者和建立者可能不是同一个用户,若是使用CURRENT_USER建立存储过程,那么在调用时,该过程以当前登陆用户的身份执行。
为此,过程的建立者必须授予当前用户执行该过程的权限。

若是以DEFINER建立存储过程,那么在调用时,该过程将以建立者身份执行,这是建立存储过程时默认的选项。

授予其余用户执行存储过程的权限:

GRANT EXECUTE ON 过程名称 TO 其余用户;

用户在执行其余用户的过程时,要在过程名前加上模式名。

在存储过程当中能够定义变量、类型、子程序、游标等元素,定义的方法与在匿名块中彻底相同。

这里再也不详细描述。

存储过程的声明部分开始于关键宇AS ,结束于关键字BEGIN ,并且不须要使用关键字DECLARE 。
存储过程的可执行部分是它的主要部分,它能够包含SQL语句和流控制语句,是存储过程功能的集中体现。
异常处理部分用来处理存储过程在执行过程当中可能出现的错误。

例如,下面的代码用来建立存储过程total_income ,它的功能是计算某部门员工的总收入。
这个过程有一个参数,表明部门编号,并指定了默认值。
这样,在调用时,若是提供了参数,则计算指定部门的数据,不然将计算全部员工的数据。

create or replace
PROCEDURE total_income(d_no IN integer:=0)
AUTHID DEFINER
AS
total number;
BEGIN
if d_no=0 then --表示全部部门
SELECT sum(sal+nvl(comm, 0)) INTO total FROM emp;
else --仅表示指定的部门
SELECT sum(sal+nvl(comm, 0)) INTO total
FROM emp
WHERE deptno=d_no;
END if;
dbms_output.put_line ('总收入:'|| total);
END;

存储过程建立之后,就能够随时调用执行了。

在SQL*plus 中调用存储过程的命令是EXECUTE ,命令的使用格式为:
EXECUTE 过程名(实际参数)

例如,要计算部门10的员工总收入和应缴的税,则能够如下形式调用刚才建立的存储过程total income 。

EXECUTE total_income(10)

若是要在一个PL/SQL块中调用存储过程,则不须要EXECUTE命令,只要经过过程名和实际参数就能够调用,调用的格式为:

过程名(实际参数);

每一个用户均可以执行本身建立的存储过程,若是要执行其余用户的存储过程,则须要具备对该存储过程的EXECUTE权限。
为此,存储过程的全部者要将EXECUTE权限授予这个用户。
授予EXECUTE权限的语句格式为:

GRANT EXECUTE ON 过程名 TO 用户; 

例如,存储过程total_income的全部者要将它的执行权限授予用户scott,则能够执行下面的SQL语句:

GRANT EXECUTE ON total_income TO scott;

若是要删除一个存储过程,能够执行DROP命令,这个命令的格式为:
DROP PROCEDURE 过程名

存储函数

存储函数也是一种存储程序,它被建立后便存储在数据库中,用户能够直接调用。

存储函数与存储过程的区别在于,存储函数必须向调用环境返回一个执行结果。
通常状况咱们是把存储函数做为一个表达式来使用的,它可用于普通表达式可以使用的场合,这是由于每一个函数都有一个返回值,在调用存储函数时,这个返回值即是存储函数的执行结果。
例如,能够将存储函数赋给一个变量,或者将这个函数与另外一个表达式进行计算等。
建立存储函数的语法格式为:

CREATE OR REPLACE FUNCTION 函数名(参数1,参数2 ...)RETURN 返回类型

AUTHID CURRENT_USER | DEFINER

AS

  声明部分

BEGIN

  可执行部分

EXCEPTION

  异常处理部分

END;

能够看出,建立存储函数的格式与建立存储过程的格式大体相同,只有三个不一样的地方,第一,用FUNCTION关键字代替了PROCEDURE关键字,以代表建立的对象是存储函数,第二,在参数列表以后用RETURN关键字规定了存储函数返回值的类型, 第三,在存储函数的可执行部分至少有一条RETURN语句,将执行结果返回给调用者。
在存储函数的可执行部分中,可能会出现多条RETURN语句,用于向调用者返回不一样的数据,可是通过逻辑处理后,只能有一条RETURN语句被执行,保证从存储函数中返回一个肯定的数据,这样就符合了程序的“单出口”的原则。
若是用户要在本身的模式中建立存储函数,须要具备CREATE FUNCTION的系统权限,若是要在其余模式中建立存储函数,则须要具备CREATE ANY FUNCTION的系统权限
例如,下面的存储函数用来计算每一个员工的总收入。

这个函数有两个参数,即工资和奖金,它的功能是求出工资和奖金之和,而后将结果返回。
建立这个函数的语句为:

create or replace
FUNCTION total_income_1(sal number,comm number)
RETURN number
AS
result number:=0;
BEGIN
result:=sal+nvl(comm,0);
RETURN result;
END;

若是要利用这个存储函数求员工的总收入,能够将这个函数用在SELECT语句中,做为SELECT语句的一个表达式,而且向它传递实际参数,最后获得它的计算结果。
例如:

SELECT ename,total_income_1(sal,comm) as total FROM emp;

再好比,下面的存储函数用于计算员工应缴的我的所得税,这个函数以部门号为参数,计算该部门中所有员工的所得税总和。
假设税率为3% ,该函数用SUM 函数计算全体员工的工资总和,而后乘以3% ,并将最后的结果返回。
函数的代码以下所示:

create or replace
FUNCTION tax_per_depart(dno integer) RETURN number
AS
result number:=0;
BEGIN
SELECT sum(sal)*0.03 INTO result FROM emp
WHERE deptno=dno
GROUP BY deptno;
RETURN result;
END;

与其余存储函数同样,这个函数能够用在SELECT语句中,也能够在其余匿名块存储过存储函数中调用执行。
例如,在下面的匿名块中调用了该函数,计算部门20 的所得税。

DECLARE
dno integer;
total_tax number;
BEGIN
dno :=20;
total_tax:=tax_per_depart(dno);
dbms_output.put_line('Total tax of department' || dno || 'is:' || total_tax);
END;

每一个用户均可以直接调用本身建立的存储函数,若是要调用其余用户的存储函数,则须要具备对相应存储函数的EXECUTE权限。
为此,存储函数的全部者要将EXECUTE权限授予适当的用户。
授予EXECUTE权限的语句格式为:

GRANT EXECUTE ON 函数名 TO 用户名;

例如,存储函数total_income的全部者要将它的执行权限授予用户scott,则能够执行下面的SQL语句:

GRANT EXECUTE ON total_income TO scott;

若是要删除一个存储函数,能够执行DROP命令,这个命令的格式为:

DROP FUNCTION 函数名;

总之,存储过程和存储函数都是存储程序,它们的区别在于存储过程没有返回值,只能被单独调用执行,在功能上相似于一条命令,而存储函数有返回值,能够用在SELECT语句和运算表达式中,它的做用至关于一个普通的表达式。
在存储过程和存储函数中均可以定义子程序,这里把重点放在了存储过程和存储函数自己的使用上,对子程序在存储过程和存储函数中的用法没有进行描述,实际上这也是很简单的。

程序包

程序包是一种Oracle数据库对象,它是一组逻辑上相关的数据类型、变量、过程、函数和游标等的集合。

程序包被建立后,存储在数据库中,用户能够直接使用包中的数据类型和变量,也能够直接调用包中的过程和函数。
程序包有两种形式,一种是用户根据须要建立的程序包,一种是系统预约义的程序包。

这里介绍自定义程序包的建立、使用、删除等操做,以及预约义程序包的使用方法
用户能够根据须要建立本身的程序包。

在程序包中能够定义数据类型、变量、过程、函数、异常和游标等元素,这些元素具备全局的特性,能够在程序包中使用,也能够在程序包以外使用

一个程序包由两部分组成:程序包的头部和包体。

其中头部用来定义类型、变量、异常、声明游标、过程和函数,它的做用至关于程序包的接口。
在包体中能够利用头部的类型定义变量,定义过程、游标和函数的代码。
在建立程序包时,头部和包体是分别建立的,而且头部必须在包体以前建立

程序包建立以后,若是要对其功能进行修改,这时只需修改包体的代码便可,不用修改头部,仅当须要改变参数类型、参数个数等信息时,才须要修改程序包的头部。
建立程序包头部的命令是CREATE PACKAGE ,这条命令的语法格式为:
CREATE [OR REPLACE] PACKAGE 包名称

AUTHID CURRENT_USER | DEFINER

AS

  类型的定义;

  变量的定义;

  子程序的声明;

  游标的声明;

  异常的声明;

END;

其中OR REPLACE选项的做用是当指定的包已经存在时从新建立它。

AUTHID选项用来规定程序包以哪一个用户的身份执行。
这个选项有两个可选值,即CURRENT_USER和DEFINER,两者只能选择其中一个。
子程序的声明就是定义过程和函数的原型,即子程序的名称、参数和返回值,不包含它的代码部分。
类型定义部分容许用户根据须要建立本身的数据类型。
例如,要对部门员工的总收入和所得税进行统计,为此须要编写一个程序包。

在程序包中首先定义了一个记录类型total ,而后声明了一个函数tax_per_depart ,用来统计某个部门的所得税,过程total_ per_depart用来统计各个部门的员工总收入。
最后还定义了一个游标c1。

须要注意的是,在程序包的头部定义游标时须要指定它的返回类型。
如下是建立程序包employee头部的代码:

create or replace
PACKAGE employee
AS
type total is record(
dno emp.deptno%type,
total_income number
);
function tax_per_depart(dno integer) RETURN number;
procedure total_per_depart;
cursor c1 RETURN total;
END;

程序包的包体是对头部的实现,主要用来定义过程和函数的可执行代码。

建立包体的命令是CREATE PACKAGE BODY ,这条命令的语法格式为:
CREATE [OR REPLACE] PACKAGE BODY 包名

AS

  游标的实现;

  子程序的实现;

END;

其中包名与建立头部时使用的名字彻底相同。

游标的实现是指定游标中所使用的SELECT语句。
子程序的实现是写出过程和函数的代码,过程和函数的编写方法与之前介绍的方法彻底相同。
如下是建立程序包employee的包体的代码。

CREATE OR REPLACE PACKAGE BODY employee
AS
CURSOR c1 RETURN total is --定义游标
SELECT deptno, sum(sal) FROM emp GROUP BY deptno;
FUNCTION tax_per_depart(dno integer) --定义函数tax_per_depart
RETURN number
AS
result number;
BEGIN
SELECT SUM(sal)*0.03 INTO result FROM emp
WHERE deptno=dno;
RETURN result;
END; --函数tax_per_depart结束
PROCEDURE total_per_depart --定义过程total_per_depart
AS
depart TOTAL;
BEGIN
OPEN c1;
FETCH c1 INTO depart; --利用取出游标中的数据
WHILE c1%FOUND LOOP
DBMS_OUTPUT.PUT_LINE('部门'||depart.dno||'总收入'||depart.total_income);
FETCH c1 INTO depart;
END LOOP;
CLOSE c1;
END;
END;

定义了程序包employee后,用户就能够在PL/SQL块或者SQL*Plus 中使用这个包中的类型、游标、变量、过程和函数了,使用的方法为:

包名.元素名

例如,要利用程序包employee 中的过程total_per_depart统计各个部门员工的总收入,在SQL*Plus 中调用这个过程:

exec employee.total_per_depart

再好比,在一个匿名块中调用程序包employee 中的函数tax_per_depart ,计算部门20的所得税,这个匿名块的代码为:

DECLARE
dno integer;
total_tax number;
BEGIN
dno := 20;
total_tax:=employee.tax_per_depart(dno);
dbms_output.put_line('Total tax of department '||dno||' is: '||total_tax );
END;

若是一个程序包再也不须要,咱们能够将其从数据库中删除。

删除程序包时,能够选择只删除包体,或者删除整个包。
删除整个程序包的命令是DROP PACKAGE ,它的格式为:

DROP PACKAGE 包名;

这样,程序包的头部和包体都将从数据库中被删除。
若是只删除包体,相应的命令为DROP PACKAGE BODY ,它的格式为:

DROP PACKAGE BODY 包名;

系统预约义的程序包

Oracle提供了一些预约义的程序包,利用这些包能够完成一些复杂的操做。

这些程序包提供了一些经常使用的类型、变量、过程和函数,用户能够在PL/SQL块和应用程序中直接使用它们。
正确地使用这些预约义的程序包,可使开发工做达到事半功倍的效果。

经常使用的预约义程序包及其用途以下所示:

DBMS_OUTPUT  显示基本的输入输出功能

UTL_FILE  对操做系统文件进行读,写等操做

DBMS_SQL  执行DDL语句

DBMS_PIPE  用于在两个进程间以管道方式进行通讯

DBMS_JOB  管理数据库中的做业

下面将对最经常使用的程序包DBMS_OUTPUT 、UTL_FILE和DBMS_SQL作简单的介绍。

1. DBMS_OUTPUT程序包

DBMS_OUTPUT包的功能是将PL/SQL块的执行结果显示在屏幕上,这种输出操做是经过缓冲区来完成的。

SQL*Plus 为存储程序、PL/SQL块、触发器的执行提供了-个缓冲区,用于存放程序执行期间所产生的数据,这个缓冲区以“先进先出”的方式管理其中的数据。
在默认状况下, PL/SQL块的执行结果是输出到缓冲区里的,若是进行一些特殊的设置,缓冲区中的数据就会输出到屏幕上,而后从缓冲区中清除。
DBMS_OUTPUT包提供了对缓冲区进行设置读和写等操做的功能,它提供了一系列的过程和函数,分别对缓冲区进行设置、读和写等操做。
用户利用DBMS_ OUTPUT包中的过程或函数能够向缓冲区中写人数据,也能够从缓冲区中读数据
缓冲区的设置操做主要包括使其可用和不可用等操做。

使缓冲区不可用的过程是DISABLE,这个过程能够在SQL*Plus 中以以下形式执行:
EXEC dbms_output.disable

若是要在存储程序、PL/SQL块和触发器中调用这个过程,则不须要EXEC命令,能够直接调用执行。
与DISABLE相对的操做是ENABLE过程,它可使缓冲区可用,而且能够设置缓冲区的大小。
它的调用形式为:

EXEC dbms_output.enable(缓冲区的大小)

若是在调用这个过程时不指定任何参数,则结果是使缓冲区可用,并将其大小设置为默认大小,即20 000字节。
例如,要将缓冲区的大小设置为1024字节,这个过程的调用形式为:

exec dbms_output.enable(1024)

缓冲区的写操做指的是向缓冲区中写入数据,目前容许的数据类型有数字型、字符串型和日期型。
写操做涉及的过程有如下几个:
PUT (参数):将指定的参数写入缓冲区。
PUT_LINE (参数):将指定的参数写入缓冲区,并在行末写一个换行符
NEW_LINE :在缓冲区中当前位置处写一个换行符。
缓冲区中的数据是以行的形式组织的,每行最多存储255个字符,一行写满时,自动从下一行开始继续写。
因为缓冲区的大小有限,写数据的原则是“先进先出”,当缓冲区写满时,若是还要继续写,那么最早写入缓冲区中的数据就会被从缓冲区中清除出去,以便腾出空间容
纳新数据。
PUT和PUT_LINE过程的做用都是向缓冲区当前位置写入一行数据,它们之间的区别是,PUT_LINE在写完数据后在当前行的末尾写入一个换行符,而PUT过程不写入换行符。
过程NEW_LINE 的做用仅仅是在缓冲区当前位置处写入一个换行符
实际上,调用-次过程PUT_LINE ,至关于先调用一次过程PUT ,而后再调用一次过程NEW_LINE 。
若是要使缓冲区中的数据显示在显示器上,必须使选项SERVEROUTPUT有效,这个选项的做用就是使缓冲区中的数据能够输出到屏幕上。
为了使这个选项有效,在SQL*Plus 中执行SET命令:

SET serveroutput ON

这个选项的另外一个可选值是OFF ,它的做用正好与ON相反。

为了说明这几个过程的用法,首先观察下面这个PL/SQL块的执行状况:

DECLARE
data1 integer := 100;
data2 varchar2(10) := 'Hello' ;
data3 date DEFAULT sysdate;
BEGIN
dbms_output.put(data1);
dbms_output.put_line(data2);
dbms_output.put_line(data3);
end;

缓冲区的读操做是指将缓冲区中的数据以行的形式读出来。

与缓冲区的读操做有关的过程有两个:
• GET_LINE :从缓冲区中读一行。
• GET_LINES :从缓冲区中读多行。
过程GET_LINE的做用是将目前缓冲区中最早写入的一行数据读出,并将这一行数据从缓冲区中删除。
它的调用形式为:

GET_LINE(变量,状态)

其中变量用于存放从缓冲区中读出的数据,它的类型必须与要读的数据一致。

状态也是一个变量,用来表示本次读操做是否成功,它的传递模式为OUT 。
在这个过程执行结束后,若是状态变量的值为0 ,表示成功,若是为1 ,则表示缓冲区中没有数据。
过程GET_LINES 的做用是将目前缓冲区中最早写入的几行数据读出,并将它们从缓冲区中删除。
它的调用形式为:

GET_LINES(变量,行数)

其中变量是一个集合类型变量,用来存放读到的几行数据。

行数也是一个变量,在读操做以前,这个参数用于指定须要读的行数,在读操做以后,这个参数表示实际读到的数据行数。
下面再经过一个例子说明读操做和写操做的综合应用。

DECLARE
data integer; --表示数据的变量
stat integer; --表示状态的变量
BEGIN
dbms_output.put(100);
dbms_output.put_line(200);
dbms_output.get_line(data,stat);
dbms_output.put_line ('缓冲区中的数据: ' || data) ;
dbms_output.put_line ('状态: '|| stat);
END;

DECLARE
data dbms_output.chararr;
stat integer; --表示状态的变量
BEGIN
dbms_output.put(100);
dbms_output.put_line(200);
stat := 1;
dbms_output.get_lines(data,stat);
for v_counter in 1..stat loop
dbms_output.put_line (data(v_counter)) ;
end loop;
END;

在上述PL/SQL块中,第一次向缓冲区中写100时使用了过程PUT ,写人数据后没有换行。
第二次向缓冲区中写200时使用了过程PUT LINE ,这样100和200被写在了同一行。

在读数据时使用了过程GET_LINE ,将刚才写人的一行数据读到变量data 中,因而变量data的值为100 200 。
而变量stat用来表示本次读操做是否成功,其值为0 ,表示读操做成功。

因而可知,在从缓冲区中读数据时,是以行为单位进行的,而不是以数据为单位。
实际上, DBMS_OUTPUT程序包自己并无输入输出的功能,它所能作的就是对缓冲区进行读写操做。
若是使SERVEROUTPUT选项有效,则缓冲区的内容就被输出到屏幕上, PUT和PUT_LINE过程只须要把数据写入缓冲区中就能够了,这就至关于完成了输出工做
而GET_LINE的功能是从缓冲区中读一行数据,若是缓冲区中有数据,则它把当前缓冲区中最早写入的数据读出,这就至关于完成了输入工做

2. UTL_FILE程序包

UTL_FILE程序包功能是对本地操做系统的文件进行访问。

在PL/SQL块中访问文件的能力是有限的,主要包括文件的打开、关闭、读、写等操做。
在访问文件以前,必须先打开文件,这时系统将返回一个文件标识,对文件的读、写等操做都是经过这个文件标识进行的。
文件访问完后,还应该及时关闭文件。

UTL_FILE程序包中与文件的打开关闭操做有关的函数和过程有:
• FOPEN

•IS_OPEN
• FCLOSE
• FCLOSE ALL

在访问文件以前,首先要用函数FOPEN打开文件。

这个函数的调用格式为:

FOPEN(目录,文件名,打开模式)

其中目录为文件所在的位置,它与文件名一块儿肯定了要访问的文件。

打开模式是指以什么样的方式打开文件。
UTL_FILE包规定了三种打开模式:

 r :只读方式,用于读出文件的内容。
w :写方式,用于向文件中写入数据。
a :追加方式,用于在文件末尾写入数据。

UTL_FILE程序包访问文件的功能颇有限,并非全部的文件均可以访问。

利用这个程序包只能访问指定目录中的文本文件。
为了访问某个目录中的文件,必须经过初始化参数指定这个目录,指定的格式为:
UTL_FILE_DIR=目录

例如,为了访问目录/home/oracle中的文件,须要在参数文件中添加一下内容: 

UTL_FILE_DIR=/home/oracle

若是没有初始化参数指定目录,那么在访问一个目录中的文件时, Oracle将抛出一个预约义的异常UTL_FILE.INVALID PATH 。
若是要访问全部目录中的文件,能够用“*”表明任何目录,代替上面某个具体目录,但这种做法是不提倡的,由于这将带来安全隐患。
若是文件打开成功, FOPEN 函数将返回一个FILE_TYPE类型文件标识,之后对文件的访问就是经过这个文件标识进行的。
FILE_TYPE类型是在UTL_FILE包中定义的类型,用户能够直接使用。
函数IS_OPEN用于判断一个文件是否已经被打开,它只有一个参数,就是FOPEN 函数返回的文件标识。
若是文件已经被打开,函数IS_OPEN将返回真值,不然返回假值。
文件访问结束后,应该调用过程FCLOSE关闲文件。

这个过程只有一个参数,就是FOPEN函数返回的文件标识。
若是打开了多个文件,能够调用过程FCLOSE ALL关闭全部文件,这个过程没有任何参数。
与文件的读操做有关的过程为GET_LINE ,它的调用格式为:

GET_LINE(文件标识,变量)

其中文件标识就是用函数FOPEN打开文件时的返回值。

变量是一个字符串类型的变量,用于存放从文件中读到的数据。
由于对文件的读操做是以行为单位进行的,因此这个变量要可以存放文件中的一行数据。
若是一个文件是空的,或者当前已经读到了文件末尾,这时系统将抛出异常NO_DATA_FOUND 。
下面的例子演示了文件的打开、读和关闭操做。

文件打开后将它的第一行数据读出,并输出到显示器上。

DECLARE
fp UTL_FILE.FILE_TYPE;
line VARCHAR2(100);
BEGIN
fp := UTL_FILE.FOPEN('C:\Users\Administrator\Desktop', 'a.log', 'r');
UTL_FILE.GET_LINE(fp, line);
DBMS_OUTPUT.PUT_LINE(line);
UTL_FILE.FCLOSE(fp);
END;

对文件的写操做涉及的过程较多,这里仅介绍用得最多的过程PUT_LINE 。

这个过程以的形式将数据写入文件,每写入一行,就在行的末尾添加一个换行符,它的调用形式为:
PUT_LINE(文件标识,变量)

这个过程将变量中的数据写入文件标识所表明的文件中。

在下面的例子中,首先以只读方式打开第一个文件,而后以追加方式打开第二个文件。
从第一个文件中读一行数据到变量中,在这行数据的先后各添加一个“#” 后再写入第二个文件,最后关闭两个文件。

DECLARE
fp1 UTL_FILE.FILE_TYPE;
fp2 UTL_FILE.FILE_TYPE;
line VARCHAR2(100);
BEGIN
fp1 := UTL_FILE.FOPEN('C:\Users\Administrator\Desktop', 'a.log', 'r');
fp2 := UTL_FILE.FOPEN('C:\Users\Administrator\Desktop', 'a.bak', 'a');
UTL_FILE.GET_LINE(fp1, line);
UTL_FILE.PUT_LINE(fp2, '#'||line||'#');
UTL_FILE.FCLOSE_ALL;
END;

3. DBMS_SQL包

在PL/SQL块中咱们能够利用SELECT命令从数据库中检索数据,也能够利用INSERT 、DELETE和UPDATE语句对数据库中的数据进行增长、删除、修改等操做。
可是像建立表、删除表、修改表结构这样的操做在PL/SQL块中是不能直接完成的,也就是说,在PL/SQL块中不能直接执行CREATE 、DROP 、ALTER这样的DDL命令。
若是要在PL/SQL块中进行这样的操做,就要借助于Oracle提供的程序包一-DBMS_SQL 。
DBMS_SQL包使得在PL/SQL包中执行DDL命令成为可能。

利用DBMS_SQL包执行DDL命令时,首先要打开一个游标,而后经过这个游标执行DDL命令,最后关闭这个游标。
DBMS_SQL包提供了一系列的过程和函数,利用这些过程和函数能够完成所需的操做。
用来打开游标的函数是OPEN_CURSOR ,这个函数没有任何参数。

若是游标打开成功,这个函数将返回一个整数,这个整数就是游标的标识。
之后执行SQL语句就是经过这个游标的标识进行的。
对SQL语句进行分析的过程是PARSE ,这个过程对SQL语句进行语法分析,将其与打开的游标、进行关联,而后执行这条SQL语句。
这个过程的调用格式为:
PARSE (游标标识, SQL语句,语言标志)
其中游标标识就是打开游标时的返回值。

SQL语句是须要执行的DDL命令的完整形式

语言标志指定该过程以什么样的方式处理SQL语句,这个参数有三个可选值:

• DBMS_SQL.V6 :采用Oracle6的方式处理SQL语句。
• DBMS_SQL.V7 :采用Oracle7的方式处理SQL语句。
• DBMS_SQL.NATIVE :采用通常方式处理SQL语句。
SQL语句执行结束后,应该及时关闭游标。

关闭游标的过程是CLOSE_CURSOR ,这个过程只有一个参数,就是经过函数OPEN_CURSOR打开的游标的标识。
例如,在下面的PL/SQL块中,首先打开一个游标,游标的标识为cur_1 ,而后利用这个游标执行一条SQL语句,建立表tl ,这个表有两个列, id和name 。
最后关闭这个游标。

这个块的执行结果是在当前用户的模式中建立了一个表t1 。

DECLARE
cur_1 integer;
str varchar2(100);
BEGIN
str := 'CREATE table t1(id integer,name varchar2(10 ))';
cur_1:=dbms_sql.open_cursor;
dbms_sql.parse(cur_1,str,DBMS_SQL.V7);
dbms_sql.close_cursor(cur_1);
END;

若是已经有一个同名的表存在,上述PL/SQL块执行时将出错。

为了向用户报告出错的状况,能够在PL/SQL块中捕捉错误,并进行异常处理,将出错的状况报告给用户,这样的PL/SQL块才算是一个完整的、健壮的程序。
下面是增长了异常处理的PL/SQL块:

DECLARE
cur_1 integer;
str varchar2(100);
already_exists EXCEPTION;
PRAGMA EXCEPTION_INIT(already_exists,-00955);
BEGIN
str := 'CREATE table t1(id integer,name varchar2(10 ))';
cur_1:=dbms_sql.open_cursor;
dbms_sql.parse(cur_1,str,DBMS_SQL.V7);
dbms_sql.close_cursor(cur_1);
EXCEPTION
WHEN already_exists THEN
dbms_output.put_line ('须要建立的表已经存在');
END;

在这个块中定义了一个异常already_exists ,而后将它与错误号,-00955 关联起来。

错误号-0955表明的错误状况是指定的名称已经被其余对象使用。
这样当发生这个错误时,系统将抛出异常already_exists 。
在块的最后,进行的异常的处理,将错误的状况显示给用户。
实际上,在PL/SQL块中还有一种执行DDLDCL语句的方法,那就是把这样的语句做为EXECUTE IMMEDIATE命令参数
EXECUTE IMMEDIATE命令的功能是执行动态的SQL语句,它的参数能够是一个变量或一个表示SQL语句的字符串,还能够是用“||”符号链接在一块儿的若干字符串等。
例如:

declare
sql_stmt varchar2(100) := ' CREATE TABLE t1(id number,name char(10))';
begin
EXECUTE IMMEDIATE sql_stmt;
EXECUTE IMMEDIATE ' GRANT select,update on t1 to shu';
EXECUTE IMMEDIATE 'DROP TABLE t1';
end;

与存储程序有关的数据字典 

在数据库中,存储过程、存储函数以及程序包的信息是存放在数据字典中的。

与存储程序有关的数据字典有:

USER_PROCEURES

USER_OBJECTS

USER_SOURCE

USER_ERROR

下面是有关数据字典ALL_PROCEDURES的介绍:

ALL_PROCEDURES lists all functions and procedures that are accessible(可访问的) to the current user, along with associated properties(与之关联的属性).

 

For example,ALL_PROCEDURES indicates whether or not a function is pipelined, parallel enabled or an aggregate function(代表一个函数是不是一个管道类型的,可并行或者是一个汇集函数).

If a function is pipelined or an aggregate function, the associated implementation type(关联的实现类型) (if any(若是有的话)) is also identified(识别).

Related Views

  • DBA_PROCEDURES lists all functions and procedures available in the database, along with associated properties.

  • USER_PROCEDURES lists all functions and procedures owned by the current user, along with associated properties.It does not contain the OWNER column.

Column Datatype NULL Description

OWNER

VARCHAR2(128)

 

Owner of the procedure

OBJECT_NAME

VARCHAR2(128)

 

Name of the object: top-level function, procedure, or package name

PROCEDURE_NAME

VARCHAR2(128)

 

Name of the procedure

OBJECT_ID

NUMBER

 

Object number of the object

SUBPROGRAM_ID

NUMBER

 

Unique subprogram identifier(惟一子程序标识)

OVERLOAD

VARCHAR2(40)

 

Overload unique identifier

OBJECT_TYPE

VARCHAR2(13)

 

The typename of the object

AGGREGATE

VARCHAR2(3)

 

Indicates whether the procedure is an aggregate function (YES) or not (NO)

PIPELINED

VARCHAR2(3)

 

Indicates whether the procedure is a pipelined table function(管道表函数 (YES) or not (NO)

IMPLTYPEOWNER

VARCHAR2(128)

 

Owner of the implementation type(实现类型, if any

IMPLTYPENAME

VARCHAR2(128)

 

Name of the implementation type, if any

PARALLEL

VARCHAR2(3)

 

Indicates whether the procedure or function is parallel-enabled (YES) or not (NO)

INTERFACE

VARCHAR2(3)

 

YES, if the procedure/function is a table function(表函数) implemented using the ODCI interface; otherwise NO

DETERMINISTIC

VARCHAR2(3)

 

YES, if the procedure/function is declared to be deterministic(肯定性); otherwise NO

AUTHID

VARCHAR2(12)

 

Indicates whether the procedure/function is declared to execute as DEFINER or CURRENT_USER (invoker)

ORIGIN_CON_ID

VARCHAR2(256)

 

The ID of the container where the data originates. Possible values include:

  • 0: This value is used for rows in non-CDBs. This value is not used for CDBs.

  • n: This value is used for rows containing data that originate in the container with container ID n (n = 1 if the row originates in root)

 

例如:要想查看当前用户所拥有的存储过程和存储函数,执行下面的SELECT语句:

SELECT object_name, object_type, authid FROM user_procedures;

数据字典user_objects用来存放当前用户所拥有的全部类型的数据库对象,包括表、视图、触发器、序列、存储过程、存储函数以及程序包等。

下面是有关数据字典ALL_OBJECTS的介绍:

ALL_OBJECTS describes all objects accessible to the current user.

Related Views

  • DBA_OBJECTS describes all objects in the database.

  • USER_OBJECTS describes all objects owned by the current user. This view does not display the OWNER column.

Column Datatype NULL Description

OWNER

VARCHAR2(128)

NOT NULL

Owner of the object

OBJECT_NAME

VARCHAR2(128)

NOT NULL

Name of the object

SUBOBJECT_NAME

VARCHAR2(128)

 

Name of the subobject(子对象) (for example, partition)

OBJECT_ID

NUMBER

NOT NULL

Dictionary object number of the object

DATA_OBJECT_ID

NUMBER

 

Dictionary object number of the segment that contains the object.

Note: OBJECT_ID and DATA_OBJECT_ID display data dictionary metadata(数据字典元数据). Do not confuse(迷惑) these numbers with the unique 16-byte object identifier (object ID) that Oracle Database assigns(分配) to row objects in object tables in the system.

OBJECT_TYPE

VARCHAR2(23)

 

Type of the object (such as TABLEINDEX)

CREATED

DATE

NOT NULL

Timestamp for the creation of the object

LAST_DDL_TIME

DATE

NOT NULL

Timestamp for the last modification of the object and dependent objects(依赖对象) resulting from a DDL statement (including grants and revokes)

TIMESTAMP

VARCHAR2(19)

 

Timestamp for the specification of the object (对象的时间戳格式)(character data)

STATUS

VARCHAR2(7)

 

Status of the object:

  • VALID

  • INVALID

  • N/A


若是要了解当前用户所拥有的数据库对象类型,能够执行下面的SELECT语句:
SELECT DISTINCT object_type FROM user_objects;

程序包的头部和包体的类型分别为PACKAGE和PACKAGE BODY 。
若是要查看某个数据库对象的详细信息,一样能够执行相应的SELECT语句。

例如,如下SELECT语句用来查看对象“total_income”的详细信息:

SELECT object_name, object_type, status, created FROM user_objects WHERE object_name='TOTAL_INCOME';

数据字典user_source用来存放存储过程、存储函数和程序包的源代码。

固然,这个视图的目的只是为了查看源代码, PL/SQL程序的执行并非从这里开始的,由于程序在建立时已经通过了编译,在数据库中以二进制形式存储。

所以,试图经过修改这个数据字典而达到修改存储程序的功能是行不通的。
Oracle在建立PL/SQL程序时,将按照用户在编写时的天然格式,以行的形式存储程序代码,并记录每行的行号,全部代码行合起来就是该程序的源代码。

下面是有关数据字典ALL_SOURCE的介绍:

ALL_SOURCE describes the text source of the stored objects accessible to the current user.

Related Views

  • DBA_SOURCE describes the text source of all stored objects in the database.

  • USER_SOURCE describes the text source of the stored objects owned by the current user. This view does not display the OWNER column.

Column Datatype NULL Description
OWNER VARCHAR2(30) NOT NULL Owner of the object
NAME VARCHAR2(30) NOT NULL Name of the object
TYPE VARCHAR2(12)   Type of object: FUNCTIONJAVA SOURCEPACKAGEPACKAGE BODYPROCEDURETRIGGER,TYPETYPE BODY
LINE NUMBER NOT NULL Line number of this line of source
TEXT VARCHAR2(4000)   Text source of the stored object

例如,要查看函数tax_per_depart的源代码,能够执行下列SELECT语句:
 SELECT line, text FROM user_source WHERE name='TOTAL_INCOME';

若是在建立存储过程、存储函数或者程序包时发生了语法错误, SQL*Plus将把错误信息在屏幕上显示,同时Oraclet把错误信息记录在数据字典中
数据字典user_errors就是用来存放当前用户在建立存储程序时发生的错误的。

下面是有关数据字典ALL_ERRORS的介绍:

ALL_ERRORS describes the current errors on the stored objects accessible to the current user.

Related Views

  • DBA_ERRORS describes the current errors on all stored objects in the database.

  • USER_ERRORS describes the current errors on the stored objects owned by the current user. This view does not display the OWNER column.

 

Column Datatype NULL Description
OWNER VARCHAR2(30) NOT NULL Owner of the object
NAME VARCHAR2(30) NOT NULL Name of the object
TYPE VARCHAR2(12)   Type of the object:
  • VIEW

  • PROCEDURE

  • FUNCTION

  • PACKAGE

  • PACKAGE BODY

  • TRIGGER

  • TYPE

  • TYPE BODY

  • LIBRARY(库)

  • JAVA SOURCE

  • JAVA CLASS

  • DIMENSION(维度)

SEQUENCE NUMBER NOT NULL Sequence number (for ordering purposes)
LINE NUMBER NOT NULL Line number at which the error occurred
POSITION NUMBER NOT NULL Position in the line at which the error occurred
TEXT VARCHAR2(4000) NOT NULL Text of the error
ATTRIBUTE VARCHAR2(9)   Indicates whether the error is an error (ERROR) or a warning (WARNING)
MESSAGE_NUMBER NUMBER   Numeric error number (without any prefix)(数字错误号,没有任何前缀)

例如,在建立存储函数total_income时,错把SELECT
语句中的“WHERE deptno=d_no”写成了“ WHERE deptno=ddn。”,因而发生了错误:

CREATE OR REPLACE PROCEDURE total_income(d_no IN integer:=0)
AUTHID DEFINER
AS
total number;
BEGIN
if d_no=0 then --表示全部部门
SELECT sum(sal+nvl(comm, 0)) INTO total FROM emp;
else --仅表示指定的部门
SELECT sum(sal+nvl(comm, 0)) INTO total
FROM emp
WHERE deptno=ddn;
END if;
dbms_output.put_line ('总收入:'|| total);
END;

Warning: Procedure created with compilation errors

为了肯定发生的全部错误的位置,执行下列查询语句:

SELECT sequence, line, position FROM user_errors;

为了查看第一个错误的详细信息,须要检索TEXT列的数据:

根据这些错误信息很快即可以肯定错误的缘由,从而进行纠正。

在不少状况下,发生的多个错误是由同一个缘由引发的,只要修改了出现错误的程序代码,多个错误可能一块儿消失。
这须要用户在编写程序的过程当中不断积累经验。
SQL*Plus还提供了一种查看错误信息的简便方法,用show errors命令能够查看当前发生的错误,而不须要了解数据字典的详细结构。

这个命令的用法为:

SHOW ERRORS

或者在查看错误信息时指定发生错误的对象的类型和名称,如:

SHOW ERRORS FUNCTION total_income 

在这种状况下,命令show errors的格式为:

SHOW ERRORS 对象类型 对象名称

相关文章
相关标签/搜索