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)不要忘了关闭游标变量 |