一、游标 (Cursor)
1、概念:
游标是处理数据的一种方法,为了查看或者处理结果集中的数据,游标提供了在结果集中一次一行或者多行前进或向后浏览数据的能力。可以把游标当作一个指针,它可以指定结果中的任何位置,然后允许用户对指定位置的数据进行处理。游标实际上是一种能从包括多条数据记录的结果集中每次提取一条记录的机制。游标可以被看作是一个查询结果集(可以是零条、一条或由相关的选择语句检索出的多条记录)和结果集中指向特定记录的游标位置组成的一个临时文件,提供了在查询结果集中向前或向后浏览数据、处理结果集中数据的能力。有了游标,用户就可以访问结果集中任意一行数据,在将游标放置到某行之后,可以在该行或从该位置的行块上执行操作。其实就是用于存放查询出来的多条记录的一个临时变量,我们可以从这个变量中取出我们需要的信息字段。(也可以把游标看成java中数组)
2、游标的使用步骤:
declare
(1)声明游标并连接查询语句
Cursor arr is select id, first_name, salary from emp;
(2)声明一个变量用于接收游标中的每一行数据(或者理解为数组所存储的每个对象)
a arr%rowtype;
begin
(3)打开游标
open arr;
(4)遍历游标,取行内的数据
for i in 1..6 loop 控制循环次数,并不是从几开始到从几结束
(5)每次循环,游标向下移动,并取出行内数据
fetch arr into a;
打印结果
dbms_output.put_line('编号:' || a.id || '名字:' || a.first_name || '薪水:' || a.salary);
结束循环
end loop;
(6)关闭游标
close arr;
end;
for循环遍历游标时:
自己定义record变量
自己打开游标
自己关闭游标
每次循环自己提取一行数据 给到record变量
3、游标的 %rowtype、 %found、 %notfound属性
(1)%rowtype: 得到与游标属性一致的数据(record)类型
(2)%found: 判断上次游标是否取到数据,取到数据返回true,否则返回false.
(3)%notfound: 判断上次游标是否取到数据,取到数据返回false,否则返回true.
(4)使用found属性之前游标必须是开启的,而且游标是经过是下移的,否则取到的结果为null.
declare
Cursor brr is select * from student;
b arr%rowtype;
begin
open brr; (打开游标:使用found属性的前置条件)
fetch brr into b; (第一次游标下移:使用found属性的前置条件)
while brr%found loop
dbms_output.put_line('学生姓名:'||b.studentname||' 电话:'||b.phone);
fetch brr into b;
end loop;
close brr;
end;
4、智能循环游标
智能循环就例如java中的增强型for循环,无需自己定义record变量,打开游标,每次循环取一行数据,关闭游标。这些操作智能循环都会给你做。
declare
cursor stu is select * from student;
begin
for s in student loop
dbms_output.put_line('学生姓名:'||s.studentname||' 电话:'||s.phone);
end loop;
end;
5、多表的游标
多表查询时,如果出现表名.列名的引用,游标是无法引用的,需要对其列进行重命名,也就是取别名。
declare
cursor per is select e.id e_s_id, first_name, name from s_emp e, s_dept d where e.deptid = s_id;
begin
for p in per loop
dbms_output.put_line('员工编号:'||p.e_s_id||' 员工名字:'||p.first_name||' 部门名称:'||p.name);
end loop;
end;
二、异常处理机制 (Exception)
1、概念:
在运行程序时出现的错误叫做异常。
发生异常后,语句将停止执行,控制权转移到程序的异常处理部分.(与java中运行时异常道理一样)
2、Oracle数据库常见的异常:
CURSER_ALREADY_OPEN 游标已经打开
INVALID_NUMBER 内嵌的SQL语句不能将字符转换为数字
NO_DATA_FOUND 使用 select into 未返回行,或应用索引表未初始化的元素时
TOO_MANY_ROWS 执行 select into 时,结果集超过一行
ZERO_DIVIDE 除数为0
VALUE_ERROR 赋值时,变量长度不足以容纳实际数据
SELF_IS_NULL 使用对象类型时,在 null 对象上调用对象方法
3、语法书写格式
如果不清楚具体是什么异常,抛出others,就是抛出所有异常。如java中Exception所有异常的基类(父类)。
declare
begin
dbms_output.put_line(10/0);
exception
when ohers then
dbms_output.put_line('除数不能为0');
end;
例如:
declare
stu student%rowtype;
begin
dbms_output.put_line(10/2);
select * into stu from student where studentno='1111111';
exception
when NO_DATA_FOUND then
dbms_output.put_line('无此数据');
when ZERO_DIVIDE then
dbms.output.put_line('除数不能为0');
end;
三、存储过程 (Procedure)
1、概念:
所谓存储过程,就是一段存储在数据库中执行某种功能的程序。其中包含一条或多条SQL语句,但是它的定义方式和PL/SQL中的块、包等有所区别。存储过程可以通俗地理解为是存储在数据库服务器中的封装了一段或多段SQL语句的PL/SQL代码块。在数据库中有一些是系统默认的存储过程,那么可以直接通过存储过程的名称进行调用。另外,存储过程还可以在编程语言中调用,如Java、C#等。
可以把存储过程理解为java中的自定义方法。但不是,因为存储过程没有返回值。
2、作用:
(1)简化复杂的操作:存储过程可以把需要执行的多条SQL语句封装到一个独立单元中,用户只需调用这个单元就能达到目的,这样就实现了一人编写多人调用。
(2)增加数据独立性:与视图的效果相似,利用存储过程可以把数据库基础数据和程序(或用户)隔离开来,当基础数据的结构发生变化时,可以修改存储过程,这样对程序来说基础数据的变化是不可见的,也就不需要修改程序代码了。
(3)提高安全性:使用存储过程有效降低了错误出现的几率。如果不使用存储过程要实现某项操作可能需要执行多条单独的SQL语句,而过多的执行步骤很可能造成更高的出现错误几率。
(4)提高性能:完成一项复杂的功能可能需要多条SQL语句,同时SQL每次执行都需要编译,而存储过程可以包含多条SQL语句,而且创建后只需要编译一次,以后就可以直接调用。
3、创建存储过程的语法格式
语法格式:
create (or replace) procedure 过程名称(形参列表)
is
声明区
begin
代码执行区
end;
例如
create procedure getMax(x number,y number)
is
begin
if(x>y) then
dbms_output.putline(x);
else
dbms_output.putline(y);
end if;
end;
执行创建语句的快捷键必须是F5
4、调用存储过程的方式
(1) call 调用
call getMax(4,6);
(2) execute 和 exec 调用 (exec 为 execute的简写)
execute getMax(5,4);
exec getMax(4,5);
(3) 程序代码块调用
begin
getMax(3,6);
end;
执行调用语句的快捷键F5 和 F9
5、创建或者替换存储过程的方式
create or replace procedure getMax(x number,y number)
is
begin
if(x>y) then
dbms_output.putline(x);
else
dbms_output.putline(y);
end if;
end;
6、形参的默认值
存储过程的参数是可以给默认值的,如果不给参数调用存储过程时,就将默认值作为实参赋值给形参。
如果只给一个实参,再调用存储过程时,将实参赋值给第一个参数。
create procedure getMax2(x number:=1,y number:=2)
is
begin
if (x>y) then
dbms_output.put_line(x);
else
dbms_output.put_line(y);
end if;
end;
测试:
call getMax2(4,45);
call getMax2();
call getMax2(1);
7、参数的模式
in : 只读模式,也是默认模式,参数在过程中只能由来读取
out:只写模式,参数在过程中只能用来赋值。
in out : 可读可写模式。
语法格式:过程名(参数 模式 参数类型)
create procedure getMax3(x number:=1,y number:=2,z in out number)
is
begin
if (x>y) then
z:=x;
else
z:=y;
end if;
end;
测试:
declare
z number;
begin
getMax3(5,6,z);
dbms_output.put_line(z);
end;
8、删除存储过程
drop procedure 过程名称;
例如:
drop procedure getMax3;
四、函数 (Function)
1、概念:
函数可以理解成Java中的方法。
它与存储概念也很相似,都是把一组逻辑相关的sql语句/PLSQL语句组织到一起的代码结构。
但注意存储过程无返回值,它不仅有返回值,也支持存储过程的参数模式(可读可写)。
2、自定义函数的语法格式
create or replace function 函数名(参数列表) return 返回值类型
is
声明区
begin
代码区
return 返回值;
end;
例如:
create or replace function getMax4(x number, y number) return number
is
begin
if x>y then
return x;
end if;
return y;
end;
3、调用函数和删除函数的方式
select 函数名(实参) from dual;
drop function 函数名;
4、参数模式加返回值
create or replace function getMax4(x number, y in out number) return number
is
begin
if x>y then
y:=x+y;
return x;
end if;
y:=x+y;
return y-x;
end;
测试:
declare
x number:=5;
y number:=6;
z number;
begin
z:=getMax4(x,y);
dbms_output.put_line(z);
end;
5、函数跟存储过程的区别
(1) 名称不同,函数的关键字是function,存储过程的关键字是procedure。
(2) 函数可以通过return返回数据,而存储过程无返回值。
(3) 调用方式不同:
存储过程在调用时,可以是pl/sql的一部分,也可以在sql中直接call。
函数在调用时,必须使用select组成表达式,才可以调用。
五、Oracle数据库常用的系统包
1、输出包:dbms_output
declare
begin
dbms_output.put_line('hello');
end;
2、随机数包:dbms_random
value(参数1,参数2)
参数1:随机数字产生的最小范围number类型 in 模式
参数2:随机数字产生的最大范围number类型 in 模式
返回值:number类型的浮点型随机数
例:取随机四位整数:
select trunc (dbms_random.value(1000,9999),0) from dual;
3、定时任务包:dbms_job
(1)作用:指定时间间隔内做一些重复的事情
(2)创建定时任务的步骤:
1)创建表格
2)定义序列
3)定义存储过程
4)定义并提交定时任务
(3)例:每隔10秒,向person表插入一条数据。
1)创建person表
create table person(
id number primary key,
name varchar(20) not null
);
2) 定义序列
create sequence seq_person;
3) 创建存储过程
create or replace procedure insert_person
is
begin
insert into preson values(seq_person.nextval,'电脑'||seq_person.nextval);
end;
4)创建并提交定时任务
declare
job_id binary_integer;
begin
dbms_job.submit(job_id,'insert_person();',sysdate,'sysdate+10/24/60/60');
dbms_job.run(job_id);
end;
5)删除定时任务 定时任务无法停止,只能删除。要通过可视化工具中,job选项中,查询对应定时任务的编号,在通过remove方法删除。
例如:
begin
dbms_job.remove(49); -- 49为上方的job_id值。
end;
(4)定时任务包中常用函数解析
1) submit(参数1,参数2,参数3,参数4)
作用:用来提交定时任务到数据库管理系统。
参数1:job(out模式的binary_integer类型),用来提交定时任务时接受任务编号的。
注意:编号值不是由我们自己定义的,而是由数据库管理系统自动分配的。
参数2:varchar2类型,要调用的存储过程的名称;例如:'过程名();'。
参数3:date类型,第一次执行任务的时间。
参数4:interval(varchar2类型),任务执行的间隔时间。
注意是字符串类型。而且字符串中必须是date类型,例如'sysdate+1'.
间隔时间的计算方式:参数4-参数3.
2)run(任务编号 binary_integer类型)
执行数据库管理系统中已提交的某个定时任务。
3)remove(任务编号 binary_integer类型)
移除数据库管理系统中已提交的定时任务。
无论任务是否在执行都会被移除。
六、触发器 (Trigger)
1、概念:
触发器是在事件发生时隐式地自动运行的PL/SQL程序块,不能接收参数,不能被调用。
2、作用:
不需要显示调用来执行,而是由一个事件来来促使运行。
可以通过其他Oracle事件触发调用的程序,因为触发器不能就收参数
Oracle事件包括:
1)DML操作或对视图进行类似的操作。
2)执行DDL操作。
3)数据库的启动和关闭。
3、创建触发器的语法格式
create or replace trigger 名称 before|after insert|update|delete on 表名 [for each row]
declare
声明区;
begin
触发器执行的代码块;
end;
for each row : 行级触发器:
针对每行语句,触发一次逻辑。
省略(不写for each row): 语句(表)级触发器:
每个DML语句,无论修改了多少条数据,都只触发一次。
例如:
create or replace trigger trigger_person after insert on person for each row
declare
begin
dbms_output.put_line('添加新数据了');
end;
4、触发器中的新旧数据
(1)在触发器的begin和end之间,可以使用两个已存在的对象。
:old 旧数据
:new 新数据
用法: :old.列名 || :new .列名
(2) DML操作分为三种:
insert: 只存在新数据,没有旧数据。
update: 存在新数据和旧数据。
delete: 只有旧数据,没有新数据。
(3)例
create or replace trigger trigger_update_person after on person for each row
declare
begin
dbms_output.put_line('人变了,原名:'|| :old.name || ',新名:'|| :new.name);
end;
update person set name = '人变了' where id > 10 and id < 20;
5、实现表中id主键的自增长(id序列加触发器实现)
(1)创建表
create table student (
id number primary key,
name varchar(20) not null,
age number(4)
);
(2) 创建序列
create sequence student_seq_id
increment by 1
start with 1
minvalue 1
(3) 创建触发器
create or replace trigger trigger_student_id before insert on student for each row
declare
begin
select student_seq_id.nextval into :new.id from dual;
end;
(4) 测试
insert into student (name,age) values('小泽马',20);
insert into student (name,age) values('武藤马',22);