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之后的列要与记录型变量各个字段在数目与类型上保持一致,否则程序执行时会发生错误。