一、游标

  在 PL/SQL 程序中,对于处理多行记录的事务经常使用游标来实现。游标是一个指向上下文的句柄( handle)或指针。通过游标,PL/SQL 可以控制上下文区和处理语句时上 下文区会发生些什么事情。

1.显式游标:

显式游标主要是用于对查询语句的处理,尤其是在查询结果为多条记录的情况下。

显式游标处理需四个 PL/SQL 步骤:

(1)定义游标:就是定义一个游标名,以及与其相对应的 SELECT 语句。

格式: CURSOR cursor_name[(parameter[, parameter]…)] IS select_statement;

游标参数只能为输入参数,其格式为: parameter_name [IN] datatype [{:= | DEFAULT} expression]

在指定数据类型时,不能使用长度约束。如 NUMBER(4)、CHAR(10) 等都是错误的。

(2)打开游标:就是执行游标所对应的 SELECT 语句,将其查询结果放入工作区,并且指针指向工作区的首部,标识游标结果集合。如果游标查询语句中带有 FOR UPDATE 选

项,OPEN 语句还将锁定数据库表中 游标结果集合对应的数据行。

格式: OPEN cursor_name[([parameter =>] value[, [parameter =>] value]…)];

在向游标传递参数时,可以使用与函数参数相同的传值方法,即位置表示法和名称表示 法。PL/SQL 程序不能用 OPEN 语句重复打开一个游标。

(3)提取游标数据:就是检索结果集合中的数据行,放入指定的输出变量中。

格式: FETCH cursor_name INTO {variable_list | record_variable };

(4) 对该记录进行处理;

(5)继续处理,直到活动集合中没有记录;

(6)关闭游标:当提取和处理完游标结果集合数据后,应及时关闭游标,以释放该游标所占用的系统资源, 并使该游标的工作区变成无效,不能再使用 FETCH 语句取其中数据。

关闭后的游标可以使用 OPEN 语 句重新打开。

格式:CLOSE cursor_name;

注:定义的游标不能有 INTO 子句。

实例:

declare
--定义游标
cursor c_cursor(emp_no number default 11) is select last_name,salary
from employees
where rownum < emp_no
order by salary;
v_name employees.last_name%type;
v_sal employees.salary%type;
begin
--打开游标
open c_cursor(emp_no => 20);
--提取游标数据
fetch c_cursor into v_name,v_sal; while c_cursor %found loop
dbms_output.put_line(v_name || ':' || v_sal);
fetch c_cursor into v_name,v_sal;
end loop;
--关闭游标
close c_cursor;
end;

游标属性:

%FOUND 布尔型属性,当最近一次读记录时成功返回,则值为 TRUE;

%NOTFOUND 布尔型属性,与%FOUND 相反;

%ISOPEN 布尔型属性,当游标已打开时返回 TRUE;

%ROWCOUNT 数字型属性,返回已从游标中读取的记录数。

游标的 FOR 循环:

  PL/SQL 语言提供了游标 FOR 循环语句,自动执行游标的 OPEN、FETCH、CLOSE 语句和循环语句的功能; 当进入循环时,游标 FOR 循环语句自动打开游标,并提取第一行游标数据,当程序处理完当前所提取的数 据而进入下一次循环时,游标 FOR 循环语句自动提取下一行数据供程序处理,当提取完结果集合中的所有 数据行后结束循环,并自动关闭游标。

格式:

FOR index_variable IN cursor_name[value[, value]…] LOOP

-- 游标数据处理代码

END LOOP;

注意:

index_variable 为游标 FOR 循环语句隐含声明的索引变量,该变量为记录变量,其结构与游标查询语句返回的结构集合的结构相同。在程序中可以通过引用该索引记录变量元素来读取所提取的游标数据。

如果在游标查询语句的选择列表中存在计算列,则必须为这些计算列指定别名后才能通过游标 FOR 循环语句中的索引变量来访问这列数据。

不要在程序中对游标进行人工操作;不要在程序中定义用于控制 FOR 循环的记录。因为FOR语句会自动完成以上操作。

实例:

declare
cursor c_emp(dep_id number default 50) is
select last_name,salary sal
from employees
where department_id = dep_id;
begin
for v_emp in c_emp(80) loop
dbms_output.put_line(v_emp.last_name||', '||v_emp.sal);
end loop;
end;

2.隐式游标:

对于非查询语句, 如修改、删除操作,由 ORACLE 系统自动地为这些操作设置游标并创建其工作区,这些由系统隐含创建 的游标称为隐式游标,隐式游标的名字为 SQL,这是由 ORACLE 系统定义的。对于隐式游标的操作,如定义、 打开、取值及关闭操作,都由 ORACLE 系统自动地完成,无需用户进行处理。用户只能通过隐式游标的相关属性,来完成相应的操作。在隐式游标的工作区中,所存放的数据是与用户自定义的显示游标无关的、

隐式游标属性:

SQL%FOUND 布尔型属性,当最近一次读记录时成功返回,则值为 TRUE;

SQL%NOTFOUND 布尔型属性,与%FOUND 相反;

SQL %ROWCOUNT 数字型属性, 返回已从游标中读取得记录数;

SQL %ISOPEN 布尔型属性, 取值总是 FALSE。SQL 命令执行完毕立即关闭隐式游标。

实例:

更新指定员工信息,如果该员工没有找到,则打印”查无此人”信息。

declare
v_name employees.last_name%type;
v_id employees.employee_id%type := &v_id;
begin
update employees
set last_name = 'xx'
where employee_id = v_id; if SQL%NOTFOUND then
dbms_output.put_line('查无此人');
end if;
end;

3.游标修改和删除操作:

  游标修改和删除操作是指在游标定位下,修改或删除表中指定的数据行。这时,要求游标查询语句中 必须使用 FOR UPDATE 选项,以便在打开游标时锁定游标结果集合在表中对应数据行的所有列和部分列。 为了对正在处理(查询)的行不被另外的用户改动,ORACLE 提供一个 FOR UPDATE 子句来对所选择的行 进行锁住。该需求迫使 ORACLE 锁定游标结果集合的行,可以防止其他事务处理更新或删除相同的行,直到 您的事务处理提交或回退为止。

格式:

SELECT . . . FROM … FOR UPDATE [OF column[, column]…] [NOWAIT]

注意:

如果使用 FOR UPDATE 声明游标,则可在 DELETE 和 UPDATE 语句中使用 WHERE CURRENT OF cursor_name 子句,修改或删除游标结果集合当前行对应的数据库表中的数据行。

实例:

从 EMPLOYEES 表中查询某部门的员工情况,将其工资最低定为 3000;

declare
v_dep_id employees.department_id%type := &v_dep_id;
cursor emp_cursor is
select last_name,salary
from employees
where department_id = v_dep_id
for update nowait;
begin
for emp_rec in emp_cursor loop
if emp_rec.salary < 3000 then
update employees set salary = 3000
where current of emp_cursor;
end if;
end loop;
end;

二、异常错误处理

概念:

异常情况处理(EXCEPTION)是用来处理正常执行过程中未预料的事件,程序块的异常处理预定义的错误和自定义错误,由于 PL/SQL 程序块一旦产生异常而没有指出如何处理时,程序就会自动终止整个程序运行

有三种类型的异常错误:

1. 预定义 ( Predefined )错误 ORACLE 预定义的异常情况大约有 24 个。对这种异常情况的处理,无需在程序中定义,由 ORACLE 自动 将其引发。

2. 非预定义 ( Predefined )错误 即其他标准的 ORACLE 错误。对这种异常情况的处理,需要用户在程序中定义,然后由 ORACLE 自动将 其引发。

3. 用户定义(User_define) 错误 程序执行过程中,出现编程人员认为的非正常情况。对这种异常情况的处理,需要用户在程序中定义, 然后显式地在程序中将其引发。

语法:

EXCEPTION

WHEN first_exception THEN <code to handle first exception>

WHEN second_exception THEN <code to handle second exception>

WHEN OTHERS THEN <code to handle others exception>

END;

注:异常处理可以按任意次序排列,但 OTHERS 必须放在最后.

1.处理预定义的异常

declare
--声明变量的代码
begin
--执行的代码
exception
when NO_DATA_FOUND then
dbms_output.put_line('数据库中没有编码为'|| v_empno ||'的员工');
when TOO_MANY_ROWS then
dbms_output.put_line('程序运行错误,请使用游标');
when others then
dbms_output.put_line('其他错误');
end;

2.处理非预定义的异常

  对于这类异常情况的处理,首先必须对非定义的 ORACLE 错误进行定义。步骤如下:

  1. 在 PL/SQL 块的定义部分定义异常情况:

    <异常情况> EXCEPTION;

  2. 将其定义好的异常情况,与标准的 ORACLE 错误联系起来,使用 PRAGMA EXCEPTION_INIT 语句:

    PRAGMA EXCEPTION_INIT(<异常情况>, <错误代码>);

  3. 在 PL/SQL 块的异常情况处理部分对异常情况做出相应的处理。

实例:

declare
--声明其他变量的代码
deptno_remaining exception; -- -2292 是违反一致性约束的错误异常的编号
pragma exception_init(deptno_remaining, -2292);
begin
--执行的代码
exception
when deptno_remaining then
dbms_output.put_line('违反数据完整性约束');
when others then
dbms_output.put_line(sqlcode || '--' || sqlerrm);
end;

注:SQLCODE 返回错误代码数字 SQLERRM 返回错误信息.

3.处理用户自定义的异常

当与一个异常错误相关的错误出现时,就会隐含触发该异常错误。用户定义的异常错误是通过显式使 用 RAISE 语句来触发。当引发一个异常错误时,控制就转向到 EXCEPTION 块异常错误部分,执行错误处理代码。

对于这类异常情况的处理,步骤如下:

1. 在 PL/SQL 块的定义部分定义异常情况:

   <异常情况> EXCEPTION;

2. RAISE <异常情况>;

3. 在 PL/SQL 块的异常情况处理部分对异常情况做出相应的处理。

实例:

declare
--声明其他变量的代码
no_result exception;
begin
--执行update代码
if sql%notfound then
raise no_result;
end if;
exception
when no_result then
dbms_output.put_line('数据更新失败');
when others then
dbms_output.put_line('出现其他异常');
end;

三、存储函数与过程

  ORACLE 提供可以把 PL/SQL 程序存储在数据库中,并可以在任何地方来运行它。这样就叫存储过 程或函数。过程和函数统称为 PL/SQL 子程序,他们是被命名的 PL/SQL 块,均存储在数据库中,并 通过输入、输出参数或输入/输出参数与其调用者交换信息。过程和函数的唯一区别是函数总向调 用者返回数据,而过程则不返回数据。

1.创建函数

建立内嵌函数:

格式:

CREATE [OR REPLACE] FUNCTION function_name
[ (argment [ { IN | IN OUT }] Type,
argment [ { IN | OUT | IN OUT } ] Type ]
[ AUTHID DEFINER | CURRENT_USER ]
RETURN return_type
{ IS | AS }
<类型.变量的说明>
BEGIN
  FUNCTION_body
EXCEPTION
  其它语句
END;

说明:
1) OR REPLACE 为可选. 有了它, 可以或者创建一个新函数或者替换相同名字的函数, 而不会出现冲突

2) 函数名后面是一个可选的参数列表, 其中包含 IN,OUT 或 IN OUT 标记, 参数之间用逗号隔开。IN 参数标记表示传递给函数的值在该函数执行中不改变;OUT 标记表示一个值在函数中进行计算并通过该参数传递给调用语句; IN OUT 标记表示传递给函数的值可以变化并传递给调用语句。若省略标记, 则参数隐含为 IN。

3) 因为函数需要返回一个值, 所以 RETURN 包含返回结果的数据类型。

实例:获取某部门的工资总和

create or replace function get_salary(
dept_id employees.department_id%type,
emp_count out number)
return number
is v_sum number;
begin
select sum(salary),count(*) int v_sum, emp_count
from employees
where department_id = dep_id; return v_sum;
exception
when no_data_found then
dbms_output.put_line('您需要的数据不存在');
when others then
dbms_output.put_line(sqlcode||':'|| sqlerrm);
end;

调用函数:

declare
v_num number;
v_sum number;
begin
v_sum := get_salary(80, emp_count => v_num);
dbms_output.put_line('80号部门的工资总和:'||v_sum||',人数:'||v_num);
end;

2.存储过程

创建存储过程:

语法:

CREATE [OR REPLACE] PROCEDURE Procedure_name
[ (argment [ { IN | IN OUT }] Type,
argment [ { IN | OUT | IN OUT } ] Type ]
[ AUTHID DEFINER | CURRENT_USER ]
{ IS | AS }
<类型.变量的说明>
BEGIN
<执行部分>
EXCEPTION
<可选的异常错误处理程序>
END;

实例:删除指定员工记录

create or replace procedure del_emp(
v_empid in employees.employee_id%type)
is no_result exception;
begin
delete from employees
where employee_id = v_empid; if sql%notfound then
raise no_result;
end if; dbms_output.put_line('编号为:'||v_empid||'的员工已被除名');
exception
when no_result then
dbms_output.put_line('您要删除的数据不存在');
when others then
dbms_output.put_line(sqlcode||'--'||sqlerrm);
end;

四、触发器

定义:  

触发器类似过程和函数,都有声明,执行和异常处理过程的 PL/SQL 块。触发器在数据库里以独立的对象存储,它与存储过程不同的是,存储过程通过其它程序来启动运行或 直接启动运行,而触发器是由一个事件来启动运行。即触发器是当某个事件发生时自动地隐式运行。并且, 触发器不能接收参数。所以运行触发器就叫触发或点火(firing)。ORACLE 事件指的是对数据库的表进行的 INSERT、UPDATE 及 DELETE 操作或对视图进行类似的操作。

分类:

DML 触发器

ORACLE 可以在 DML 语句进行触发,可以在 DML 操作前或操作后进行触发,并且可以对每个行或语句操作上进行触发。

替代触发器

由于在 ORACLE 里,不能直接对由两个以上的表建立的视图进行操作。所以给出了替代触发器。

系统触发器

它可以在 ORACLE 数据库系统的事件中进行触发,如 ORACLE 系统的启动与关闭等。

组成:

触发事件:即在何种情况下触发 TRIGGER; 例如:INSERT, UPDATE, DELETE。

触发时间:即该 TRIGGER 是在触发事件发生之前(BEFORE)还是之后(AFTER)触发,也就是触发事件和 该 TRIGGER 的操作顺序。

触发器本身:即该 TRIGGER 被触发之后的目的和意图,正是触发器本身要做的事情。 例如:PL/SQL 块。

触发频率:说明触发器内定义的动作被执行的次数。即语句级(STATEMENT)触发器和行级(ROW)触发器。 语句级(STATEMENT)触发器:是指当某触发事件发生时,该触发器只执行一次; 行级(ROW)触发器:是指当某触发事件发生时,对受到该操作影响的每一行数据,触发器都单独执行一 次。

语法:

CREATE [OR REPLACE] TRIGGER trigger_name
{BEFORE | AFTER }
{INSERT | DELETE | UPDATE [OF column [, column …]]}
ON [schema.] table_name
[FOR EACH ROW ]
[WHEN condition]
trigger_body;

注意:

BEFORE 和 AFTER 指出触发器的触发时序分别为前触发和后触发方式,前触发是在执行触发事件之前触 发当前所创建的触发器,后触发是在执行触发事件之后触发当前所创建的

触发器。

FOR EACH ROW 选项说明触发器为行触发器。行触发器和语句触发器的区别表现在:行触发器要求当一 个 DML 语句操做影响数据库中的多行数据时,对于其中的每个数据行,只要它们符合触发约束条件,均激 活一次触发器;而语句触发器将整个语句操作作为触发事件,当它符合约束条件时,激活一次触发器。当省略 FOR EACH ROW 选项时,BEFORE 和 AFTER 触发器为语句触发器,而 INSTEAD OF 触发器则为行触发器。

当触发器被触发时,要使用被插入、更新或删除的记录中的列值,有时要使用操作前或操作后的列的值。实现:

:NEW 修饰符访问操作完成后列的值

:OLD 修饰符访问操作完成前列的值

实例:建立一个触发器, 当职工表 emp 表被删除一条记录时,把被删除记录写到职工表删除日志表中去。

create table emp_his as
select * from emp
where 1 = 2 create or replace trigger del_emp_trigger
before delete on emp for each row
begin
insert into emp_his(deptno, empno, ename, job, mgr, sal,comm,hiredate)
values(:old.deptno, :old.empno, :old.ename, :old.job, :old.mgr, :old.sal,:old.comm,:old.hiredate);
end;

Oracle学习DaySix(PL/SQL续)的更多相关文章

  1. oracle学习之pl/sql使用==转载

    PLSQL循序渐进全面学习教程(全):https://blog.csdn.net/spark998/article/details/2065269

  2. 每周一书《Oracle 12 c PL(SQL)程序设计终极指南》

    本周为大家送出的书是<Oracle 12 c PL(SQL)程序设计终极指南>,此书由机械工业出版社出版, 孙风栋,王澜,郭晓惠 著. 内容简介: <Oracle 12c PL/SQ ...

  3. Oracle学习笔记三 SQL命令

    SQL简介 SQL 支持下列类别的命令: 1.数据定义语言(DDL) 2.数据操纵语言(DML) 3.事务控制语言(TCL) 4.数据控制语言(DCL)  

  4. 《oracle每日一练》免安装Oracle客户端使用PL/SQL

    免安装Oracle客户端使用PL/SQL Oracle客户端挺招人烦的,部署连接它的应用通常需要先安装它的客户端,安装程序要求在目标机器上写注册表,假设你没有洁癖的话,你仍可能被下面的事情绊住:当你的 ...

  5. Oracle 客户端安装 + pl/sql工具安装配置

    Oracle 客户端安装 +  pl/sql工具安装配置 下载oracle客户端,并在本地安装. 11g下载地址为: http://www.oracle.com/technetwork/databas ...

  6. oracle instantclient basic +pl/sql 安装和配置

    oracle instantclient basic +pl/sql 安装和配置 大家都知道,用PL/SQL连接Oracle,是需要安装Oracle客户端软件的,oracle客户端有点大,比较耗资源. ...

  7. Oracle数据库之PL/SQL触发器

    Oracle数据库之PL/SQL触发器 1. 介绍 触发器(trigger)是数据库提供给程序员和数据分析员来保证数据完整性的一种方法,它是与表事件相关的特殊的存储过程,它的执行不是由程序调用,也不是 ...

  8. Oracle数据库之PL/SQL包

    Oracle数据库之PL/SQL包 1. 简介 包(PACKAGE)是一种数据对象,它是一组相关过程.函数.变量.常量和游标等PL/SQL程序设计元素的组合,作为一个完整的单元存储在数据库中,用名称来 ...

  9. Oracle数据库之PL/SQL过程与函数

    Oracle数据库之PL/SQL过程与函数 PL/SQL块分为匿名块与命名块,命名块又包含子程序.包和触发器. 过程和函数统称为PL/SQL子程序,我们可以将商业逻辑.企业规则写成过程或函数保存到数据 ...

  10. Oracle数据库之PL/SQL异常处理

    Oracle数据库之PL/SQL异常处理 异常指的是在程序运行过程中发生的异常事件,通常是由硬件问题或者程序设计问题所导致的. PL/SQL程序设计过程中,即使是写得最好的程序也可能会遇到错误或未预料 ...

随机推荐

  1. MinTTY终端模拟器要点

    1.MinTTY是一个Cygwin和MSYS的虚拟终端: 2.支持复制和粘贴操作,支持鼠标操作和右键快捷菜单: 3.支持文本.文件.文件夹的拖放: 4.支持中文,支持UTF-8字符集,支持IME(In ...

  2. [名词解释 ] transparent

    1.材质,效果透明. 2.思想透明,容易获取(思维简单,单纯) 3.后台静默(of a process or interface) functioning without the user being ...

  3. vs2015编译caffe

    有些时候,需要在python3的环境下import caffe,需要用vs2015在python3的环境下,编译pycaffe. microsoft的windows版本的caffe,依赖的库Nuget ...

  4. linux日常使用指令总结

    linux 日常指令总结(ubuntu): ls -lha 所有文件及权限 df -h 系统磁盘空间 du -sh 当前目录大小 du -ah --max-depth=1 显示目录下所有的文件和文件夹 ...

  5. 安装weblogic

    附:wls1036_generic.jar 链接:https://pan.baidu.com/s/1W5g-SHeKL96yrOeDKJJoxw 提取码:vxft 注:以下安装步骤是一个前辈整理的,我 ...

  6. PHP获取POST的几种方法

    一.PHP获取POST数据的几种方法 方法1.最常见的方法是:$_POST['fieldname'];说明:只能接收Content-Type: application/x-www-form-urlen ...

  7. 转入墙内:SAS HBA crossflashing or flashing to IT mode, Dell Perc H200 and H310

    Default firmware for this guide is:2118it.binVersion 20.00.07.00Release date: 11-FEB-16 所有资源已转到百度盘: ...

  8. 简单测试 Kotlin native 性能

    准备 一直使用kotlin JVM平台开发服务器的应用,最近想试试看 Kotlin native的性能. 我使用的是 kotlin native 1.3.21,要使用他非常的简单,下载最新的 IDEA ...

  9. Map、List、Set在Java中的各种遍历方法

    一.Map的4种遍历 Map<String, String> map = new HashMap<String, String>(); map.put("姓名&quo ...

  10. Webpack学习-Plugin

    原文地址:http://wushaobin.top/2019/03/15/webpackPlugin/ 什么是Plugin? 在Webpack学习-工作原理(上)一文中我们就已经介绍了Plugin的基 ...