3.4 PL/SQL如何访问数据库

编写PL/SQL块的主要目的是对数据库进行访问,因此,在PL/SQL块中可以包含SELECT语句、DML语句,还可以包含DCL语句。需要注意的是,在PL/SQL块中不能直接包含DDL语句,如果要利用PL/SQL块完成诸如创建表、修改表结构等操作,需要通过其他方法。

通过SQL语句以及流控制语句,可以编写复杂的PL/SQL块,对数据库进行复杂的访问。由于PL/SQL块一般是在应用程序中调用执行,而不是以交互方式执行,所以在PL/SQL块中的SQL语句与一般的SQL语句有所不同,这一点在学习时要注意。

3.4.1 如何对数据进行查询

在PL/SQL块中通过SELECT语句从数据库中检索数据。由于要对数据进行查询以及处理,而不仅仅是显示出来,所以SELECT语句需要采用下面的特殊格式:


SELECT列1,列2……INTO变量1,变量2……

FROM表

……


与一般的SELECT语句相比,PL/SQL块中的SELECT语句使用了INTO子句,其余部分是相同的。利用INTO子句,把查询到的数据存放在变量中,以进行相应的处理。例如,下面的例子首先从部门表中检索部门30的名称、地址等信息,分别存放在变量d_name和d_location中,然后从雇员表中查询该部门中员工的工资、奖金总和,分别存放在变量total_sal和变量total_comm中,最后打印出这些信息。为了使程序更加灵活,首先定义了一个变量dno,用来存放部门编号,这样在SELECT语句中就可以使用这样的变量。


DECLARE

dno integer;

d_name dept.dname%type;

d_location dept.loc%type;

total_sal number;

total_comm number;

BEGIN

dno:=30;

SELECT dname, loc INTO d_name, d_location

FROM dept

WHERE deptno=dno;

dbms_output.put_line('名称:'||d_name||'位置:'||d_location);

SELECT sum(sal),sum(nvl(comm,0))INTO total_sal, total_comm

FROM emp

WHERE deptno=dno;

dbms_output.put_line('工资总和:'||total_sal||'奖金总和:'||total_comm);

END;


程序执行的结果为:


SQL>/

名称:SALES 位置:CHICAGO

工资总和:9400 奖金总和:2200


需要注意的是,在SELECT语句中,需要查询的列与INTO子句中的变量在数目、类型上要一致,否则会发生错误。

在执行SELECT语句时,可能会发生两种例外情况,一是没有查询到满足条件的数据,二是存在多行满足条件的数据,这就是通常所说的异常。Oracle预定义了一些异常,例如在第一种情况下发生的是异常NO_DATA_FOUND,在第二种情况下发生的是异常TOO_MANY_ROWS。对于这样的异常必须做出处理,否则会影响PL/SQL块的正确执行。

为了使程序简洁,在INTO子句中可以使用一个记录型变量,以代替多个单独的变量,把查询的数据存储在这个记录型变量中。例如,对上面的PL/SQL块进行改造,首先定义一个记录类型department以及一个该类型的变量depart。然后定义一个记录类型employee以及一个该类型的变量employ。在变量depart中存放需要查询的部门的信息,在变量employ中存放员工的总工资和总奖金。


DECLARE

dno integer;

TYPE department is RECORD

(d_no integer,

d_name dept.dname%type,

d_location dept.loc%type

);

depart department;

TYPE employee is RECORD

(total_sal number,

total_comm number

);

employ employee;

BEGIN

dno:=30;

SELECT deptno, dname, loc INTO depart

FROM dept

WHERE deptno=dno;

dbms_output.put_line('名称:'||depart.d_name||'位置:'||depart.d_location);

SELECT sum(sal),sum(nvl(comm,0))INTO employ

FROM emp

WHERE deptno=dno;

dbms_output.put_line('工资总和:'||employ.total_sal||'奖金总和:'||employ.total_comm);

END;


在使用记录型变量时要注意,SELECT之后的列要与记录型变量各个字段在数目与类型上保持一致,否则程序执行时会发生错误。