pl/sql基本语法
-----------------------自定义异常--------------------------------------------------------------------
定义部分: 声明异常变量 exception_name exception;
执行部分:抛出异常 raise exception_name;
异常处理部分: 捕获异常
------------------------创建过程----------------------------------------------------------------------
create or replace procedure procedure_name(参数) is / as local variable declaration begin executable statements exception exception handlers end;
执行存储过程: in 模式调用存储过程exec procedure_name()
out 模式调用存储过程时,需要在其他pl/sql中进行调用
inout模式调用存储过程时,需要在其他pl/sql中进行调用
过程参数三种模式
in:用于接受调用程序的值
默认的参数模式
out :用于向调用程序返回值
in out:用于接受程序的值,并向调用程序返回更新的值
例 1:编一个 输入两个数字并使得两个数字交换输出的存储过程
定义
create or replace procedure procedure1(p1 in out number, p2 in out number) as v_temp number; begin v_temp :=p1; p1 := p2; p2 :=v_temp; end;
调用:
declare num1 number :=100; num2 number :=200; begin proceduref1(num1,num2); dbms_output.put_line( 'num1 =' || num1,'num2 =' ||num2); end;
--------------------------------函数---------------------------------------------------------------------------------
函数是可以返回值的命名的pl/sql子程序
定义函数的一些限制 :函数只能接受in参数,而不能接受out 或者 in out模式参数
形参不能是pl/sql类型,只能是数据库类型
函数的返回类型也必须是数据库类型
创建函数的语法:
create or replace function function_name(参数) return 数据类型 as 变量 begin executable statements; return result; exception exception handlers; end;
例1:
create or replace function function1 return varchar2 as begin return ‘你好,朋友’; end;
sql.plus 中调用函数方法:
select function1 from dual;
在pl/sql代码块中运行方法:
declare ss varchar2(20); begin ss:=function1; dbms_output.put_line(ss); end;
例2:创建一个函数,可以接受用户输入的学号,得到该学生的名次,并输出这个名次
学生成绩表(sno,name,score)
create or replace function function2(sno1 int) return int as score1 number; mingci1 number; begin select score into score1 from student where sno = sno1; select count(*) into mingci1 from student where score >score1; return mingci+1; end;
------------------------- 索引 ---------------------------------------------------------------------------
索引分类:B树索引、位索引
1.创建标准索引
create index index_name
on table_name(column1…);
2,创建唯一索引
create unique index index_name
on table_name(column1…);
3,.创建位索引
create bitmap index index_name on table_name(column1…);
------------------------------------ 事务 -----------------------------------------------------------
原子性、一致性、隔离性、永久性
设置自动提交:set autocommit on/off
----------------------------------- 游标 --------------------------------------------------------------------
游标分类:隐式游标:在pl/sql程序中执行dml sql语句时自动创建隐式游标,名称固定:sql
显示游标 :显示游标用于处理返回多行的查询
ref游标 :ref游标用于处理运行时才能确定的动态sql查询的结果
游标的四种属性:
%found sql语句影响了一行或者多行时为true
%notfound sql语句没有影响任何行时为true
%rowcount sql语句影响的行数
%isopen 游标是否打开
声明游标、打开游标、提取游标数据、关闭游标
两个常见异常 :
没有查找出数据:no_date_found
返回过多行数:too_many_rows
例1 使用游标取出学生记录表中的所有记录 student(sno,sname,sage)
declare stu1 student%rowtype; cursor mycursor is select * from student; begin open mycursor; fetch mycursor into stu1 ; while mycursor%found loop dbms_output.put_line('学号是:' || stu1.sno || '学生名为:' || stu1.sname ||'学生年龄为;' || stu1.sage); end loop; close mycursor; end;
对显示游标添加参数
declare sno1 student.sno%type; stu1 student%rowtype; cursor mycursor( input_no number) is select * from student where sno >input_no; begin sno1 :=&学生学号; open mycursor(sno1); fetch mycursor into stu1 ; while mycursor%found loop dbms_output.put_line('学号是:' || stu1.sno || '学生名为:' || stu1.sname ||'学生年龄为;' || stu1.sage); end loop; close mycursor; end;
允许使用游标删除或更新活动集中的行 声明游标时必须使用 select …for update语句
声明时
cursor cursor_name is select statement for update;
在更新语句时
update table_name set set_clause where current of cursor_name --当缺少该行时,会对表中的所有数据行进行更新两次
例3:使用游标 对2号或者3号的学生进行记录修改
declare stu1 student%rowtype; cursor mycursor is select * from student where sno=2 or sno =3 for update; begin open mycursor; fetch mycursor into stu1 ; while mycursor%found loop update student set sno = sno +10; where current of mycursor; fetch mycursor into stu1; end loop; close mycursor; end;
显示游标例
两张表 student(xh number , xm varchar2(10)) address (xh number, zz varchar2(10)完成 给表student添加一列zz 是varchar2(10)类型,再从address中,将zz字段的数值取出来,对应的插入到表student新增的zz列中
alter table studnet add zz varchar2(10); declare xh1 number; zz1 varchar2(10); cursor cursor1 is select xh,zz from address; begin open cursor1; fetch cursor1 into xh1,zz1 ; while cursor1%found loop update student set zz=zz1 where xh = xh1; end loop; close cursor1; end;
循环游标:只能进行select 不能进行update
写法:
for <record_index> in <cursor_name> loop <executable statements> end loop;
declare stu1 student%rowtype; cursor mycursor is select * from student; begin for cur_2 in mycursor loop dbms_output.put_line('学号是:' || cur_2.sno || '学生名为:' || cur_2.sname ||'学生年龄为;' ||cur_2.sage); end loop; end;
在大量数据处理情况下:
fetch cursor_name bulk collect into variable; --比 fetch cursor_name into variable --效率高、速度快
ref游标
创建ref游标变量两个步骤:
声明ref游标类型
声明ref游标类型的变量
--用于声明ref游标类型的语法: type <ref_cursor_name> is ref cursor [return <return_type>];
--打开游标 变量的语法 open cursor_name for select_statement;
例子:使用ref游标查询student(sno,sname)表中的姓名
declare type refcur is ref cursor; cursor2 refcur; tab varchar2(50); tab_name varchar2(50); sno1 student.sno%type; sname1 student.sname%type; begin tab_name := '&tab'; if tab_name ='studnet' then open cursor2 for select sno,sname form student; fetch cursor2 into sno1,sname1; while corsor2%found loop dbms_output.put_line('学号为:' || sno1 || '姓名为:' || sname1); end loop; close cursor2; else dbms_output.put_line('输入为不正确的表名'); end if; end;
显示游标和ref游标一起使用
例:学生表student(xh number ,kc varchar2(10)); 生成student2表(xh number ,kc varchar(50)) 要求对应于每个学生,求出他的总的 选课记录,把 每个学生的选课记录插入到student2表中,即将一位学生的所有记录 放入student2表中的kc中
1 declare 2 xh1 student.xh%type; 3 kc1 varchar2(50) := ''; --保存对应学生的课程 4 kc2 varchar2(50); 5 6 cursor cursor1 is select distinct(xh) from student; 7 type refcur is ref cursor; 8 cursor2 refcursor; 9 10 begin 11 open cursor1 ; 12 fetch cursor1 into xh1; 13 while cursor1%found loop 14 kc1 := ''; 15 open cursor2 for select kc from student where xh = xh1; 16 fetch cursor2 into kc2; 17 while cursor2%found loop 18 kc1 := kc1 || kc2; 19 fetch cursor2 into kc2; 20 end loop; 21 close cursor2; 22 insert into student2 values(xh1,kc1); 23 commit; 24 fetch cursor1 into xh1; 25 end loop; 26 close cursor1; 27 end;
----------------------------- 触发器 ------------------------------------------------------------
create [or replace] trigger trigger_name after / before / instead of -- after触发器的工作原理:先保存数据库数据的更新,再激活触发器 --before触发器的工作原理:先激活触发器,再保存更新数据库数据 [ insert] [ [or] update [of column_list] ] [ [or] delete] on table_or_view_name [referencing {old [as] old / new [as] new} ] [for each row] --行级触发器,如果没有该行就是表级触发器 [when condition] pl/sql_block; --new 代表用户即将插入数据库中的某行记录的新表值 --old 代表即将删除的该行数据记录得旧表值
触发器中不能使用 :rollback、commit、create、 dorp、 alter、 savepoint等内容
触发条件谓词:当插入数据时触发谓词inserting
当进行更新数据时的触发谓词updating
当进行删除数据时的触发谓词deleting
例1:当用户插入或更新 成绩表中的记录时候,就输出一个提示“触发器响应了”
create or replace trigger trigger1 before insert or update on 成绩表 begin dbms_output.put_line('触发器响应了'); end;
例2:当向学生表中插入数据时,需要控制学生学号不可以为负数
create or replace trigger trigger2 before insert on student for each row begin if now.sno <0 then raise_application_error(-2001,'学号错误,不能插入表中'); end if; end;
例3:当向学生表 中插入 数据时,需要控制学生学号 不能为负数,如果为负数,则将负数改为绝对值的正数插入
create or replace trigger trigger3 before insert on student for each row begin if :now.no<0 then now.sno := -now.sno; end if; end;
常用的系统变量
ora_client_ip_address --返回客户端的ip地址 ora_database_name --返回当前 数据库名 ora_login_user --返回登录用户名 ora_dict_obj_name --返回ddl 操作所对应的数据库对象名 ora_dict-obj_type --返回ddl操作所对应的数据库对象类型
instead of触发器:修改视图中,非键值表中的列 定义在视图上,用来替换实际的操作语言
例4:学生表(sno,sname,sage)
住址表(sno,zname)
视图(sno,sname,zname)更新视图 将学生名为kite的住址换成安徽
create or replace trigger trigger4 instead of update on view_stu_add for each row declare aa number :=0; begin select sno into aa from student where sname = old.sname; delete from address where sno = aa; insert into address values(aa,:new.zz); end; update view_stu_add set zname ='安徽' where sname = 'kite';
例5:当用户对学生成绩表student(sno,sname,score)进行增删改的时候,将当时情况输出 出来,增加时,记录增加的信息,更新时,记录更新前、后的记录信息,删除的时候 ,记录删除的记录
create or replace trigger trigger5 before insert or update or delete on student for each row begin if inserting then dbms_output.put_line('插入的学生 学号是:'|| new.sno || '姓名是:' || new.sname ||'成绩是 :'|| new.score); end if; if updating then dbms_output.put_line('原始学生的学生 学号是:'|| old.sno || ‘姓名是:’ || old.sname ||'成绩是 :'|| old.score); dbms_output.put_line('新的学生的学生 学号是:'|| new.sno || '姓名是:' || new.sname ||'成绩是 :'|| new.score); end if; if deleting then dbms_output.put_line('删除的学生 学号是:'|| old.sno || ‘姓名是:’ || old.sname ||'成绩是 :'|| old.score); end if; end;
-------------------------------- 程序包 ---------------------------------------------------------------
程序包 :是对于相关过程、函数、变量、游标和异常等对象的封装
程序包的组成部分:包规范(包头)、包主体(包体)组成
包头:公用类型的变量、常量、异常 、过程、函数等的 声明
包体:私有类型的变量、常量、异常 、过程、函数等的 声明,以及包头内的过程、函数的实现。
创建包头的语句:
create or replace package package_name is/as public item declarations --公有对象:在包的外部也可使用 subprogram specification end package_name;
创建包体的语句:
create or replace package body package_name is/as private item declarations --私有对象:只能在包体之内使用,范围超出包体则不可再使用 subprogram bodies begin initialization end package_name;
程序包中的存储过程:
例1: 两张表 student(sno,snme,sage)、address(sno,zz)
create or replace package pack1 is aa int :=9; --公共变量,包外依然可访问应用 procedure insert_student(a1 in student%rowtype); --声明存储过程 procedure uppdate_student(a2 in student%rowtype);--声明存储过程 end pack1;
create or replace package body pack1 is bb int :=5; --私有变量 使用范围 包的内部 procedure insert_student(a1 in student%rowtype) is begin insert into student(sno,sname,sage) values(a1.sno,a1.sname,a1.sage); commit; dbms_output.put_line(pack1.bb); end insert_student; procedure update_student(a2 in student%rowtype) --根据传入参数的学号,修改学生名 is begin update student set sname = a2.sname where sno = a2.sno; commit; end update_student;
end pack1; execute dbms_output.put_line(pack1.aa); --可输出结果 execute dbms_output.put_line(pack1.bb);--不可输出结果
包的使用:在pl/sql程序块中
declare a1 student%rowtype; begin a1.sno :=8; a1.sname:='AA'; a1.sage "=24; pack1.insert_studnet(a1); end; declare a2 student%rowtype; begin a2.sno :=8; a2.sname :='BB'; a2.sage = 27; pack1.update_studnet(a2); end;
程序包中的游标
游标的定义分为游标规范和游标主体两部分
在包规范中声明游标规范时必须使用return子句指定游标的返回类型
return 子句指定的数据类型可以是:
用%rowtype 属性引用表定义的记录类型;
定义的记录类型,例如:type emprectyp is record( emp _id integer, salary real)来定义的
不可以是number、varchar2、%type等类型
程序包内,使用显示游标
create or replace package pack2 is cursor mycursor return student%rowtype; procedure mycursor_use; end pack2;
create or replace package body pack2 is cursor mycursor return studnet%rowtype is select * from student; procedure mycursor_use is stu_rec studnet%rowtype; begin open mycursor; fetch mycursor into stu_rec; while mycursor%found loop dbms_output.put_line( '学号是' || stu_rec.sno || ‘姓名是’ || stu_rec.sname || '年龄是' || stu_rec.sage); fetch mycursor into stu_rec; end loop; close mycursor; end mycursor_use; end pack2; exec pack2.mycursor_use;
程序包内,使用 ref 游标
create or replace package pack3 is type refcur is ref cursor; procedure mycursor_use; end pack3; create or replace package body pack3 is procedure mycursor_use is mycursor refcur; stu_rec student%rowtype; begin open mycursor for select * from student; fetch mycursor into stu_rec; while mycursor%found loop dbms_output.out_line('学号是:' || stu_rec.sno || '姓名是:'||stu_cur.sname); fetch mycursor into stu_rec; end loop; close mycursor; end mycursor_use; end pack3;
--执行
execute pack3.mycursor_use;