`

oracle 包, 游标, 函数 function , 存储过程 PROCEDURE , 触发器 Trigger

 
阅读更多

1、 ORACLE函数定义
function uf_execute_sql(as_where varchar2, as_sql varchar2) return varchar2 is
v_ret varchar2(30);
begin
execute immediate as_sql
into v_ret
using as_where; //using 后的参数为as_sql中的参数,若有多个依次添加,用逗号分割
return v_ret;
end;
2、 创建包
创建Oracle包是我们在使用Oracle数据库时最常见的操作之一,下面就为您介绍创建Oracle包规范的语法,希望对您能有所帮助。
包是一种将过程、函数和数据结构捆绑在一起的容器;包由两个部分组成:外部可视包规范,包括函数头,过程头,和外部可视数据结构;另一部分是包主体(package body),包主体包含了所有被捆绑的过程和函数的声明、执行、异常处理部分。
打包的PL/SQL程序和没有打包的有很大的差异,包数据在用户的整个会话期间都一直存在,当用户获得包的执行授权时,就等于获得包规范中的所有程序和数据结构的权限。但不能只对包中的某一个函数或过程进行授权。包可以重载过程和函数,在包内可以用同一个名字声明多个程序,在运行时根据参数的数目和数据类型调用正确的程序。
创建Oracle包必须首先创建包规范,创建Oracle包规范的语法如下:
1. CREATE [OR REPLACE] PACKAGE package_name
2. {AS|IS}
3. public_variable_declarations |
4. public_type_declarations |
5. public_exception_declarations |
6. public_cursor_declarations |
7. function_declarations |
8. procedure_specifications
9. END [package_name]
创建包主体使用CREATE PACKAGE BODY语句:
1. CREATE [OR REPLACE] PACKAGE BODY package_name
2. {AS|IS}
3. private_variable_declarations |
4. private_type_declarations |
5. private_exception_declarations |
6. private_cursor_declarations |
7. function_declarations |
8. procedure_specifications
9. END [package_name]
私有数据结构是那些在包主体内部,对被调用程序而言是不可见的。
********************存储过程************************************
子程序 是已经命名的PLSQL块,他们存储在数据库中,可以为他们指定参数,可以在客户端和
应用程序中调用它们。
子程序包括 存储过程 和 函数,程序包 是存储过程和 函数的集合。
存储过程--语法:
CREATE [OR REPLACE] PROCEDURE procedure_name
[(parameter_list)]
{IS|AS}
[local_declarations]
BEGIN
executable_statements
[EXCEPTION
exception_handlers]
END [procedure_name];
语法说明:
procedure_name 是过程名字
parameter_list 是参数列表
local_declarations 是局部声明
executable_statements 是可执行语句,
execption_handlers是 异常处理程序
-------
create or replace procedure wyd_print(times number)
is
i number :=0;
begin
loop
i :=i+1;

DBMS_OUTPUT.PUT_LINE('第'||i||'次 循环!!');

exit when i>= times;

end loop;
end;
/
直接调用存储过程:
exec wyd_print(20)
execute wyd_print(30);

过程参数模式
调用程序是通过参数向被调用的过程传递值的。
参数传递的模式有3种:IN ,OUT ,IN OUT 。也就是输入,输出,输入 输出
定义过程参数的语法:
parameter_name [IN |OUT |IN OUT] datatype [{:=| DEFAULT} expression]

参数IN模式 是默认模式
如果要指定OUT | IN OUT 模式参数 要 明确指定

---------
实例:
CREATE OR REPLACE PROCEDURE mypar(a IN number,b OUT number,c IN OUT number)
IS

BEGIN
DBMS_OUTPUT.PUT_LINE('a -->'||a);
DBMS_OUTPUT.PUT_LINE('b -->'||b);
DBMS_OUTPUT.PUT_LINE('c -->'||c);

--a:=111;
b:=222;
c:=333;

DBMS_OUTPUT.PUT_LINE('a -->'||a);
DBMS_OUTPUT.PUT_LINE('b -->'||b);
DBMS_OUTPUT.PUT_LINE('c -->'||c);

END mypar;
/
-----

declare
aa number:=11;
bb number:=22;
cc number:=33;
begin
DBMS_OUTPUT.PUT_LINE('before aa -->'||aa);
DBMS_OUTPUT.PUT_LINE('before bb -->'||bb);
DBMS_OUTPUT.PUT_LINE('before cc -->'||cc);
mypar(aa,88,cc);
DBMS_OUTPUT.PUT_LINE('after aa -->'||aa);
DBMS_OUTPUT.PUT_LINE('after bb -->'||bb);
DBMS_OUTPUT.PUT_LINE('after cc -->'||cc);

end;
/

注意几点:
(1)IN类型参数 在 过程中不能 再给赋值
(2)OUT INOUT 类型 可以进入后赋值。
(3)OUT 类型参数在调用过程传入参数时无效,
(4)OUT ,IN OUT 类型参数 在调用过程时传入的必须是变量

---------
一个过程创建了,将执行权限授予其他用户
语法:
GRANT EXECUTE ON procedure_name TO USER_Name; //授权给特定用户执行过程的权限
GRANT EXECUTE ON procedure_name TO public ; //授权给所有数据库用户执行过程的权限
查看数据库里面的存储过程:
select object_name from user_objects where object_type='PROCEDURE';
select substr(object_name,1,20) object_name,object_type from user_objects where object_type='PROCEDURE';
select substr(object_name,1,10) object_name,object_type from user_objects;
删除一个过程:
DROP procedure procedure_name;

____________________________________________________________________
_______________ 函数的 定义 和 使用 ____________________
____________________________________________________________________
函数与过程相似,也是数据库中存储的已经命名的PL/SQL块。
函数的主要特性:
(1)必须有一个返回值
(2)函数不能单独执行,只能通过SQL语句 或者PL/SQL程序块来调用。
函数定义 -- 语法:
CREATE [OR REPLACE] FUNCTION function_name
[(parameter1,parameter2...)]
RETURN datatype
{IS|AS}
[local_declarations]
BEGIN
Exexutable_Statements;
[EXCEPTION
Exception_handlers;]
END;
/
注意:
(1)函数只能带有 IN 参数,而不能带有 IN OUT 或 OUT 参数。
(2)形式参数必须只能使用数据库类型,不能使用PL/SQL类型。
(3)函数返回类型也必须是数据库类型。
--------------
创建一个函数:
create or replace function fun_sum(a number,b number)
return number
IS
BEGIN
return a+b;
END;
--------------
通过SQL来执行函数:
SELECT function_name[(parameter1,parameter2...)] FROM DUAL;
select fun_sum(5,6) from dual;
--------------
查看数据库里面的用户创建的函数:
select object_name from user_objects where object_type='FUNCTION';
select substr(object_name,1,20) object_name,object_type from user_objects where object_type='FUNCTION';
--------------
函数的授权:
GRANT EXECUTE ON function_name TO USER_Name; //函数的使用权授予特定的用户
GRANT EXECUTE ON function_name TO public; //函数的使用权授予数据库中所有用户
example:
GRANT EXECUTE ON fun_sum to public;
--------------
*** 自主事务处理
自主事务处理 是有另一个事务处理(主事务处理) 启动的独立事务处理。
举例:
//P1就是 自主事务处理
CREATE OR REPLACE PROCEDURE p1
AS
PRAGMA AUTONOMOUS_TRANSACTION; --就这句话,让事务处理独立开来了
BEGIN
END p1;
/
CREATE OR REPLACE PROCEDURE p2
AS
BEGIN
...
p1;
...
END p2;
/
p2 过程 调用 了P1 过程,但是 p1过程声明了事务独立,
使得p1的运行对p2没有直接影响。

删除一个函数:
语法:
DROP FUNCTION Function_name;
Example:
drop FUNCTION fun_sum;
****************** 包 的创建 和使用 ****************
----------------------------------------------------------------
程序包是一种数据库对象,它是对相关PL/SQL类型,子程序,游标,异常,变量
和常量的封装。
创建一个程序包 有两个步骤:
(1) 创建 程序包规范。(也可以说成是 ‘声明程序包’)
基本语法:
CREATE [OR PEPLACE] PACKAGE package_name
IS|AS
[public type and item declarations]
[subprogram specifications]
END [package_name];
/
------------
(2) 创建 程序包主体。(也可以说成是‘实现程序包’)
基本语法:
CREATE [OR REPLACE] PACKAGE BODY package_name
IS|AS
[Public type and item declarations]
[Subprogram bodies]
[BEGIN
Initialization_statements]
END [package_name];
package_name
Public type and item declarations 声明变量,常量,游标,异常 或者 类型。
Subprogram bodies 定义公共和私有PL/SQL子程序
------------------
实际例子:
(1)创建程序包规范:
CREATE OR REPLACE PACKAGE wyd_package
IS
PROCEDURE wyd_print(name varchar2);
FUNCTION wyd_sum(a number,b number) return number;
END wyd_package;
(2)创建程序包主体:
CREATE OR REPLACE PACKAGE BODY wyd_package
AS
--实现wyd_print 存储过程
PROCEDURE wyd_print(name varchar2) IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Hello,'||name);
END wyd_print;

--实现wyd_sum 函数
FUNCTION wyd_sum(a number,b number) RETURN NUMBER
IS
BEGIN
return a+b;
END wyd_sum;

END wyd_package;
-----------
调用创建的包中的存储过程 和 函数
set serveroutput on
exec wyd_package.wyd_print('WangYuDong');
select wyd_package.wyd_sum(12,55) from dual;
-----------
查看数据库里面的用户创建的程序包:
select object_name from user_objects where object_type='PACKAGE';
select substr(object_name,1,20) object_name,object_type from user_objects;
select substr(object_name,1,20) object_name,object_type from user_objects where object_type='PACKAGE';

删除一个程序包:
语法:
DROP PACKAGE PACKAGE_name;
Example:
drop package wyd_package;
********************** 触发器 *****************************
触发器 是当特定事件出现时自动执行的代码块。
触发器与过程的区别在于:
过程 是由用户 或 程序 显式调用的,
而触发器是不能被直接调用的。Oracle会在事件请求触发器时,执行适当的触发器。
触发器 可以用加强Oracle的 默认功能,提供高度可定制的数据库。触发器能够执行
的功能有:
》自动生成数据
》强制复杂的完整性约束
》自定义复杂的安全权限
》提供审计和日志记录
》启用复杂的业务逻辑
触发器的一般语法:
CREATE [OR REPLACE] TRIGGER trigger_name
{BEFORE|AFTER|INSTEAD OF}
{INSERT|DELETE|UPDATE[OF column[,column]...]}
[OR {INSERT|DELETE|UPDATE [OF column[,column]...]}]
ON [schema.]table_or_view_name
[REFERENCING [NEW AS new_row_name] [OLD AS old_row_name]]
[FOR EACH ROW]
[WHERE(condition)]
[DECLARE
variable_declation]
BEGIN
statements;
[EXCEPTION
exception_handlers]
END [trigger_name];
----------------
select to_char(sysdate,'yyyy-mm-dd hh12:mi:ss') from dual;
----------------
实例01:
CREATE OR REPLACE TRIGGER s_emp_trigger
BEFORE
INSERT OR DELETE OR UPDATE OF salary,name,id on s_emp
FOR EACH ROW
DECLARE
e_outtime EXCEPTION;
time_now varchar2(2);
time_upper varchar2(2) :='08';
time_lower varchar2(2) :='19';
BEGIN
time_now :=to_char(sysdate,'hh24');
IF time_now <time_upper or time_now>time_lower THEN
RAISE e_outtime;
ELSE DBMS_OUTPUT.PUT_LINE('修改数据库成功!!');
END IF;
EXCEPTION
WHEN e_outtime THEN
RAISE_APPLICATION_ERROR(-2222,'数据库在工作时间以外不允许修改!!');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('出现未知异常!!');
END;
/
上面的触发器 是 限制 在 一天中8 点到19点 以外的时间修改表 s_emp;
----------------
测试 触发器
insert into S_EMP(ID,NAME,SALARY)
VALUES('5','yangguo','5000');
----------------
实例02:
CREATE OR REPLACE TRIGGER student_trigger
BEFORE
INSERT OR UPDATE OF name on student
FOR EACH ROW
BEGIN
:new.name:='wangyudong';
END;
/
----
上面的触发器是把要插入的值进行了更换,使得原先插入的name的value被修改为'wangyudong'
insert into student(id,name,class)
values('2','zhang','class2');
/
______________________________
触发器的组成部分:
1,触发器语句
触发器语句是那些可以导致触发器的事件,
既在表或者视图上执行的INSERT,DELETE和UPDATE之类的
DML(Data manipulation language 数据库操纵语言)语言,
在模式对象上执行的DDL(Data definition language
数据库定义语句)语句或数据库事件。
[insert|delete|update] of [column,[column..]]on [tableName |viewName]
or
[insert|delete|update] of [column,[column..]]on [tableName |viewName]
[FOR EACH ROW]//写的话是行级 ,不写就是语句级别

2,触发器限制
触发器限制条件包含一个boolean表达式,该值必须为真才能激活触发器。
如果该值为假或未知,将不会触发。
[WHEN(condition)]

3,触发器操作
触发器操作是触发器的主体,包含一些SQL语句和代码,这些代码在执行触发器语句
且触发器限制条件的值为真时运行。
行级触发器允许触发操作中的语句访问行的列值。
[DECLARE
variable_declation]
BEGIN
statements;
[EXCEPTION
exception_handlers]
END [trigger_name];

----------------------------------------------------------------
触发器类型:
1,行级别触发器
行级别触发器对DML语句影响的每个行执行一次。如果是UPDATE语句,可能影响
多行,也就多次执行触发器。
可以在CREATE TRIGGER命令中指定FOR EACH ROW子句创建行级别触发器

new.column 表示要插入更新的列的新值
old.column 表示要插入更新的列的旧值
:new.column := new_value 表示给新的列值变量赋值
用到new.column and old.column 一般在 行级别触发器的 BEFORE 触发器里面使用

2,语句级别触发器
语句级别触发器对每一个DML语句执行一次。如果一个INSERT语句在表中插入200行,那么
在表上的INSERT语句级别触发器只执行一次。
语句级别的触发器以便不用于处理于数据相关的操作,通常用于强制实施在表上的安全
措施。语句级别触发器是CREAT TRIGGER命令创建的触发器的默认类型。

3,INSTEAD OF 触发器
INSTEAD OF 触发器是在视图上而不是在表上定义的触发器,它是用来替换所有使用实际语句
的触发器。这样的触发器可以用于克服Oracle在任何视图上设置的限制,允许拥护修改不能直接
修改的视图。
举例:
SET SERVEROUTPUT ON

CREATE OR REPLACE TRIGGER student_trigger
INSTEAD OF
INSERT OR UPDATE OF name on student_view
FOR EACH ROW
BEGIN
DBMS_OUTPUT.PUT_LINE('这视图是不允许被操作的!!');
END;
/

4,模式触发器
相当于是帐户级别触发器
在Oracle数据库中有多个帐户。
可以在模式级别的操作上建立触发器,如 CREATE,ALTER,DROP,GRANT,
REVOKE和 TRUNCATE 等DDL语句。
用户可以创建触发器类防止删除自己创建的表。
模式触发器提供的主要功能是阻止DDL操作以及在发生DDL操作的时候提供
额外的安全监控。
语法:
______________________________________
CREATE OR REPLACE TRIGGER trigger_name
{BEFORE|AFTER}trigger_event
ON [schema.]SCHEMA
WHEN(trigger.condition)

trigger_body;
_______________________________________
实例:
(1)我们来创建一个表来存放删除表的信息:
create table dropped_object(
obj_name varchar2(30),
obj_type varchar2(30),
drop_date DATE
);

(2)我们来创建一个模式级别的触发器。用来记录被删除的对象
CREATE OR REPLACE TRIGGER log_drop_obj
AFTER DROP ON SCHEMA
BEGIN
INSERT INTO dropped_object(obj_name,obj_type,drop_date)
values(ORA_DICT_OBJ_NAME,ORA_DICT_OBJ_TYPE,SYSDATE);
END;



5,数据库级别触发器
可以创建在数据库事件上的触发器,包括启动,关闭,服务器错误,登陆和注销等。
这些都是实例范围的,不与特定的表或视图关联。可以使用这种类型的触发器自动进行
数据库的维护和审计活动。
语法-例子:
CREATE OR REPLACE TRIGGER system_startup
AFTER STARTUP ON DATABASE
BEGIN
--Do something
END;
/
_______________________________________________________________
_______________________________________________________________
启用和禁用触发器
触发器一旦创建,默认就立即生效。我们也可以手动将触发器停止或者启动。
起用或者禁用已知道的触发器
语法:
ALTER TRIGGER trigger_name {ENABLE|DISABLE};
起用或者禁用在特定表上建立的所有触发器
语法:
ALTER TABLE table_name {ENABLE|DISABLE} ALL TRIGGERS;

查看有关触发器的信息
DESC USER_TRIGGERS;
SELECT TRIGGER_NAME FROM USER_TRIGGERS;
删除触发器
语法:
DROP TRIGGER <trigger_name>;
_____________________________________________________________________________________________________________________
*************************************** 游标管理********************************************************************
游标是构建在PL/SQL中,用来查询数据,获得记录集合的指针。他可以让开发者一次访问结果集中一行。
游标的分类:
游标分为:
静态游标
|
----隐式游标
|
----显式游标 (特殊的有循环游标)

REF游标(引用游标)
//**********************************
隐式游标
所有的SQL数据操纵语句 (QML)都有隐式声明游标,称为隐式游标。
隐式游标是用户不能直接命名和控制的游标。
隐式游标的四个属性:
%FOUND
只有用在DML语句影响一行的多行的时候,%FOUND属性返回TRUE,否则返回FALSE

%NOTFOUND
与%FOUND属性的作用相反,如果DML没有影响任何行,返回TRUE,否则返回FALSE

%ROWCOUNT
返回DML影响数据库表的行数,值是 0 到 多

%ISOPEN
返回游标是否被打开的消息。在执行SQL语句之后,Oracle自动关闭SQL游标,所以
隐式游标的%ISOPEN属性始终是关闭的。

SQL%FOUND
SQL%NOTFOUND
SQL%ROWCOUNT
SQL%ISOPEN
----------------
操作
set serveroutput on
begin
insert into s_emp(id,name,salary) values('1','tom','4000');
--要执行的sql语句
IF sql%found THEN
DBMS_OUTPUT.PUT_LINE('用sql%found得知表更新了!');
ELSE
DBMS_OUTPUT.PUT_LINE('用sql%found得知表没更新!');
END IF;
--用sql%found来判断是否更新数据库了
IF sql%notfound THEN
DBMS_OUTPUT.PUT_LINE('用sql%notfound 得知表没有更新!!');
ELSE
DBMS_OUTPUT.PUT_LINE('用sql%notfound 得知表更新了!!');
END IF;
DBMS_OUTPUT.PUT_LINE('表更新了---->'||sql%rowcount||'行');
--用sql%rowcount来查看更新了多少行
if sql%isopen then
dbms_output.put_line('cursor is open');
else
dbms_output.put_line('cursor is close');
end if;
--用sql%isopen来查看游标是否关闭了

DBMS_OUTPUT.PUT_LINE('end!!');
end;
/
----------------
----------------------------------------------------------------------------------------------
显式游标:
显式游标是用户声明的游标,查询返回的行集合可以包含 0行到多行。
显式游标的标准操作过程:
(1)声明游标。
(2)打开游标。
(3)从游标中获取记录。
(4)关闭游标。
------------------------
(1)声明游标:
CURSOR cursor_name [(parameter[,parameter]....)]
[RETURN return_type]
is select_statement;

cursor_name : 游标名称
parameter : 游标指定输入参数
return_type : 定义游标提取的行的类型
select_statement : 指游标定义的查询语句
(2)
OPEN cursor_name [(parameters)];
(3)
FETCH cursor_name INTO variables;
cursor_name : 指游标的名字
variables : 变量名
(4)
// 在处理完游标中的所有行之后,必须关闭游标,以释放分配给游标中的所有资源。
CLOSE cursor_name;

-----------
%FOUND
如果执行最后一条FETCH语句成功提取行,返回TRUE,否则返回FALSE
%NOTFOUND
如果执行最后一条FETCH语句成功提取行,返回FALSE,否则返回TRUE
%ISOPEN
如果游标关闭,返回FALSE,游标开启,返回TRUE
%ROWCOUNT
返回到目前位置游标提取的行数。当成功FETCH一行后,数量+1;

-------
实例:
set serveroutput on
declare
emp_id s_emp.id%type;
emp_name s_emp.name%type;
emp_salary s_emp.salary%type;
cursor emp_cur is
select id,name,salary from s_emp;
begin
open emp_cur;
loop
fetch emp_cur into emp_id,emp_name,emp_salary;
exit when emp_cur%notfound;
dbms_output.put_line('emp id -->'||emp_id||',emp name-->'||emp_name||',emp salary-->'||emp_salary);

end loop;
close emp_cur;
end;
/
-------
显式游标的特殊情况:循环游标
可以使用循环游标简化显式游标的处理代码。 循环游标隐式打开游标,自动从活动集获取行,然后在处理完所有行时关闭游标。
循环游标自动创建%ROWTYPE类型的变量并且将此变量用作记录索引。
语法:
FOR record_index IN cursor_name
LOOP
executable_statements;
END LOOP;
-----------
具体实例:
SET SERVEROUTPUT ON
DECLARE
CURSOR emp_cur is
select id,name,salary from s_emp;
BEGIN
--其中emp_rec 是一个存放一行的变量。我们在使用前不需要先声明。直接用
for emp_rec in emp_cur
LOOP
DBMS_OUTPUT.PUT_LINE('EMP ID-->'||emp_rec.id||' EMP NAME-->'||emp_rec.name||' EMP SALARY-->'||emp_rec.salary);
END LOOP;
END;

------------
REF 游标 (引用游标)
REF游标 可以在运行的时候决定执行何种查询。
使用过程:
1,创建游标
TYPE ref_cursor_name IS REF CURSOR [RETURN record_type];
注释:return 语句是可选择子句,用于指定游标提取结果集的返回类型。
如果没有return那么游标类型是一个弱类型。

2,在PLSQL的执行部分打开游标变量。用于打开REF游标的语法:
OPEN cursor_name FOR select_statement;

or OPEN cursor_name FOR dynamic_select_string [USING bing_argument_list];
----------
实例01
DECLARE
sqls VARCHAR2(200);
p_salary number:=8500;
id number;
name varchar2(50);
salary number;

TYPE cursor_salary IS REF CURSOR;
ref_cursor cursor_salary;
BEGIN
sqls :='select id from s_emp where salary>:1 ';
open ref_cursor FOR sqls USING p_salary;
DBMS_OUTPUT.PUT_LINE('薪水大于8500的人的ID有:');
LOOP
fetch ref_cursor into id;
EXIT WHEN ref_cursor%notfound;
DBMS_OUTPUT.PUT_LINE('ID='||id);
END LOOP;
--close ref_cursor;
END;
/
实例02
DECLARE
type emp is record(
id s_emp.id%type,
name s_emp.name%type,
salary s_emp.salary%type
);
p_salary number:=8500;
id number;
name varchar2(50);
salary number;

TYPE cursor_salary IS REF CURSOR RETURN emp;
ref_cursor cursor_salary;
BEGIN

open ref_cursor FOR select id,name,salary from s_emp where salary>8500;
DBMS_OUTPUT.PUT_LINE('薪水大于8500的人的ID有:');
LOOP
fetch ref_cursor into id,name,salary;
EXIT WHEN ref_cursor%notfound;
DBMS_OUTPUT.PUT_LINE('ID='||id||',name='||name||',salary='||salary);
END LOOP;
close ref_cursor;
END;
/
得出几点:
(1)在声明ref游标 的时候要用记录类型来声明 return
(2)游标查询结果<select 得出的结果>一定要和 声明的记录类型对应。
(3)不要忘了关闭游标变量
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics