游标存储过程函数触发器包_第1页
游标存储过程函数触发器包_第2页
游标存储过程函数触发器包_第3页
游标存储过程函数触发器包_第4页
游标存储过程函数触发器包_第5页
已阅读5页,还剩88页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第6章游标、存储过程、函数、包和触发器,课程描述介绍Oracle数据库程序设计中经常会用到的几个概念,即游标、存储过程、函数、包和触发器。,本章知识点,游标存储过程管理(存储过程、函数)包触发器管理,游标,PL/SQL中SELECT语句必须带INTO子句,将查询结果INTO到相应的变量中,然后再将变量的值输出。但这种SELECTINTO语句只能返回一条记录。如果SELECTINTO语句返回多条记录,就会产生系统预定义错误too_many_rows。为了解决此问题,必须使用游标。游标可以对SQL语句的处理进行显示控制,便于对表的行数据逐条进行处理。游标有两种类型:显式游标、隐式游标。,游标的基本概念(1)显式游标:是由程序员定义和命名的,并且在块的执行部分中通过特定语句操纵的内存工作区。当SELECT返回多条记录时,应显式地定义游标以处理每一行。(2)隐式游标:是由PL/SQL为DML语句和返回单行记录的SELECT语句隐式定义的工作区。游标是一个指向该内存区域的指针,是一个PL/SQL的结构。,游标的基本概念,游标的基本概念,隐式游标【例】使用SELECT语句声明隐式游标,从HR.Departments表中读取Department_name字段的值到变量DepName:DECLAREDepNamescott.Dept.Dname%Type;BEGINSELECTDnameINTODepNameFROMDeptWHEREDeptno=10;dbms_output.put_line(DepName);END;,显式游标1、显式游标的处理步骤显式游标的处理包括四个步骤:定义游标:在DECLARE说明部分定义游标,声明游标及在游标中使用的select语句。打开游标:执行游标定义时的select语句,把查询结果装入内存,游标位于结果的第一条记录。读取数据:从结果集的游标当前位置读取数据,执行完游标后移一行。关闭游标:在语句执行部分、或者出错处理部分关闭游标。,(1)定义游标定义游标时定义了游标的名字,并将该游标和一个SELECT语句相关联。定义游标的语法:CURSOR游标名(参数名1数据类型,参数名2数据类型.)ISSELECT语句;例:定义游标cursorc1isselectename,deptnofromemp;,(2)打开游标打开游标就是在接受实际参数值后,执行游标所对应的SELECT语句,将其查询结果放入内存工作区,并且指针指向工作区的首部。打开游标的语法:OPEN游标名(实际参数值1,实际参数值2.);例:打开游标OPENC1;,(3)取值到变量(需要循环)取值工作是将游标工作区中的当前指针所指行的数据取出,放入到指定的输出变量中。系统每执行一次FETCH语句只能取一行,每次取出数据之后,指针顺序下移一行,使下一行成为当前行。循环执行FETCH语句,直到整个查询结果集都被返回。取值到变量的语法:FETCH游标名INTO变量1,变量2.;,(4)关闭游标显式打开的游标需要显式关闭。游标关闭后,系统释放与该游标关联的资源,并使该游标的工作区变成无效。关闭以后不能再对游标进行FETCH操作,否则会触发一个INVALID_CURSOR错误。如果需要可以重新打开。关闭游标的语法:CLOSE游标名;例:关闭游标CLOSEC_CLASSES;,2、游标的属性从游标工作区中逐一提取数据,可以在循环中完成。但循环的开始以及结束,必须以游标的属性为依据。,游标控制语句,【例】下面介绍一个完整的游标应用实例:/*打开显示模式*/SETServerOutputON;DECLARE-开始声明部分varIdNUMBER;-声明变量,用来保存游标中的用户编号varNameVARCHAR2(50);-声明变量,用来保存游标中的用户名-定义游标,varType为参数,指定用户类型编号CURSORMyCur(varTypeNUMBER)ISSELECTUserId,UserNameFROMUsersWHEREUserType=varType;BEGIN-开始程序体OPENMyCur(1);-打开游标,参数为1,表示读取用户类型编号为1的记录FETCHMyCurINTOvarId,varName;-读取当前游标位置的数据CLOSEMyCur;-关闭游标dbms_output.put_line(用户编号:|varId|,用户名:|varName);-显示读取的数据END;-结束程序体,游标中用loopendloop结构,declarecursoremp_cursorisselectename,salfromscott.empwheredeptno=10;v_nameemp.ename%type;v_salemp.sal%type;beginif(notemp_cursor%isopen)thenopenemp_cursor;endif;loopfetchemp_cursorintov_name,v_sal;exitwhenemp_cursor%notfound;dbms_output.put_line(v_name|,|v_sal);endloop;closeemp_cursor;end;/,游标中用whileloopendloop结构,declarecursoremp_cursorisselect*fromscott.empwheredeptno=10;myrecordscott.emp%rowtype;beginopenemp_cursor;fetchemp_cursorintomyrecord;while(emp_cursor%found)loopdbms_output.put_line(myrecord.ename|,|myrecord.sal);fetchemp_cursorintomyrecord;endloop;closeemp_cursor;end;/,游标中用for结构,declarecursoremp_cursorisselect*fromscott.empwheredeptno=10;beginforemp_recordinemp_cursorloopdbms_output.put_line(emp_record.ename|,|emp_record.sal);endloop;end;/,带参数的游标,declarecursoremp_cursor(idvarchar2)isselect*fromscott.empwheredeptno=id;begindbms_output.put_line(*结果集为*);foremp_recordinemp_cursor(10)loopdbms_output.put_line(emp_record.ename|,|emp_record.sal);endloop;end;/,修改游标中的结果集,declarecursoremp_cursorisselect*fromscott.empwheredeptno=10forupdate;begindbms_output.put_line(*结果集为*);foremp_recordinemp_cursorloopupdatescott.empsetsal=sal+200wherecurrentofemp_cursor;dbms_output.put_line(emp_record.empno|,|emp_record.ename|,|emp_record.sal);endloop;end;/,Select语句代替游标名,beginforcurin(select*fromdept)loopdbms_output.put_line(cur.deptno|,|cur.dname);endloop;end;/,隐式游标使用,beginupdatedeptsetdname=dddddwheredeptno=90;ifsql%notfoundtheninsertintodept(deptno,dname)values(90,ddddd);-dbms_output.put_line(sql.deptno|,|sql.dname);endif;end;/Oracle自动分配的游标,隐含游标名为SQL。,游标属性,(1)%ISOPEN属性【例】下面的代码演示当使用未打开的游标时,将会出现错误:/*打开显示模式*/SETServerOutputON;DECLARE-开始声明部分varNameVARCHAR2(50);-声明变量,用来保存游标中的用户名varIdNUMBER;-声明变量,用来保存游标中的用户编号-定义游标,varType为参数,指定用户类型编号CURSORMyCur(varTypeNUMBER)ISSELECTUserId,UserNameFROMUsersWHEREUserType=varType;BEGIN-开始程序体FETCHMyCurINTOvarId,varName;-读取当前游标位置的数据CLOSEMyCur;-关闭游标dbms_output.put_line(用户编号:|varId|,用户名:|varName);-显示读取的数据END;-结束程序体,游标属性,【例】修改上面的程序,在使用游标之前,调用%ISOPEN属性判断游标是否打开。/*打开显示模式*/SETServerOutputON;DECLARE-开始声明部分varNameVARCHAR2(50);-声明变量,用来保存游标中的用户名varIdNUMBER;-声明变量,用来保存游标中的用户编号-定义游标,varType为参数,指定用户类型编号CURSORMyCur(varTypeNUMBER)ISSELECTUserId,UserNameFROMUsersWHEREUserType=varType;BEGIN-开始程序体IFMyCur%ISOPEN=FALSEThenOPENMyCur(2);ENDIF;FETCHMyCurINTOvarId,varName;-读取当前游标位置的数据CLOSEMyCur;-关闭游标dbms_output.put_line(用户编号:|varId|,用户名:|varName);-显示读取的数据END;-结束程序体,游标属性,(2)%FOUND属性和%NOTFOUND属性【例】%FOUND属性可以循环执行游标读取数据:/*打开显示模式*/SETServerOutputON;DECLARE-开始声明部分varNameVARCHAR2(50);-声明变量,用来保存游标中的用户名varIdNUMBER;-声明变量,用来保存游标中的用户编号-定义游标,varType为参数,指定用户类型编号CURSORMyCur(varTypeNUMBER)ISSELECTUserId,UserNameFROMUsersWHEREUserType=varType;BEGIN-开始程序体IFMyCur%ISOPEN=FALSEThenOPENMyCur(1);ENDIF;FETCHMyCurINTOvarId,varName;-读取当前游标位置的数据WHILEMyCur%FOUND-如果当前游标有效,则执行循环LOOPdbms_output.put_line(用户编号:|varId|,用户名:|varName);-显示读取的数据FETCHMyCurINTOvarId,varName;-读取当前游标位置的数据ENDLOOP;CLOSEMyCur;-关闭游标END;-结束程序体,游标属性,(3)%ROWCOUNT属性【例】只读取前2行记录:/*打开显示模式*/SETServerOutputON;DECLARE-开始声明部分varNameVARCHAR2(50);-声明变量,用来保存游标中的用户名varIdNUMBER;-声明变量,用来保存游标中的用户编号-定义游标,varType为参数,指定用户类型编号CURSORMyCur(varTypeNUMBER)ISSELECTUserId,UserNameFROMUsersWHEREUserType=varType;,游标属性,BEGIN-开始程序体IFMyCur%ISOPEN=FALSEThenOPENMyCur(1);ENDIF;FETCHMyCurINTOvarId,varName;-读取当前游标位置的数据WHILEMyCur%FOUND-如果当前游标有效,则执行循环LOOPdbms_output.put_line(用户编号:|varId|,用户名:|varName);-显示读取的数据IFMyCur%ROWCOUNT=2THENEXIT;ENDIF;FETCHMyCurINTOvarId,varName;-读取当前游标位置的数据ENDLOOP;CLOSEMyCur;-关闭游标END;-结束程序体,10.2存储过程管理,过程函数程序包区别:Procedures执行事务Functions计算结果Packages将逻辑上相关的过程和函数打包到一起相同点:存储在数据库中或者作为应用子程序而开发.,过程,CREATEPROCEDURE语句来创建过程:CREATEORREPLACEPROCEDUREIS|ASBEGINEND;参数列表:parameter_nameIN|OUT|INOUTdatatype:=|DEFAULTexpr注意:不要在参数的数据类型上指定长度,过程,【例】创建示例过程ResetPwd,此过程的功能是将表Users中指定用户的密码重置为111111:CREATEORREPLACEPROCEDUREUserMan.ResetPwd(UserIdINNUMBER)ASBEGINUPDATEUsersSETUserPwd=111111WHEREUserId=UserId;END;,例子,createorreplaceprocedureadd_emp(enonumber,namevarchar2,salnumber,jobvarchar2,dnonumber)ise_integrityexception;pragmaexception_init(e_integrity,-2291);begininsertintoemp(empno,ename,sal,job,deptno)values(eno,name,sal,job,dno);exceptionwhendup_val_on_indexthendbms_output.put_line(empno不能重复);whene_integritythendbms_output.put_line(部门号不存在);end;/,createorreplaceprocedureexchange_value(value1inoutnumber,value2inoutnumber)astemp1number;temp2number;begintemp1:=value1;temp2:=value2;value1:=value2;value2:=temp1;end;/,exchange_value执行步骤;sqlvara1number;sqlvara2number;sqlexeca1:=2009;Sqlexeca2:=2008;Sqlexchange_value(:a1;a2);Sqlselect:a1,:a2fromdual;,执行函数的几种方法,1)execprocedure_name(parameter_value)2)callprocedure_name(parameter_value)2)beginprocedure_name(parameter_value);end3)带有输出参数的过程执行varible变量类型(长度);execprocedure_name(parameter_value,:变量);print变量;(或者为select:变量fromdual),显示错误,显示具体的错误内容。Showerrors查询存储过程内容:Select*fromuser_sourcewherename=存储过程名;注:存储过程名为大写字母删除存储过程Dropprocedure存储过程名,过程,存储过程管理,过程,添加存储过程,过程,修改存储过程,创建函数,创建PL/SQL函数的目的是给调用环境返回一个值.在函数声明的时候,必须包括一个带有数据类型的RETURN子句.函数体中至少要包括一个RETURN语句.,函数,CREATEFUNCTION语句来创建函数:CREATEORREPLACEFUNCTIONRETURNIS|ASBEGINRETURNEND;,函数,createorreplacefunctionget_name(emp_numnumber)returnvarchar2asemp_nameemp.ename%type;beginselectenameintoemp_namefromempwhereempno=emp_num;Returnemp_name;end;/,函数执行1)Selectfunction_name(参数)fromdual;2)varible变量类型(长度);exec:变量:=function_name(参数);print变量;(或者为select:变量fromdual)函数信息查看同存储过程函数删除Dropfunction函数名;,函数,函数管理,函数,添加函数,函数,修改函数,存储过程和函数的主要差别有两个:一是返回值的方法不同二是调用方法不同(1)返回值的方法不同存储函数:有零个或多个参数,但不能有OUT参数。函数只返回一个值,靠RETURN子句返回。存储过程:有零个或多个参数,过程不返回值,其返回值是靠OUT参数带出来的。,存储过程与函数的区别,(2)调用方法不同调用过程的语句可以作为单独的可执行语句在PL/SQL块中单独出现。如:过程名(实际参数1,实际参数2.);函数可以在任何表达式能够出现的地方被调用,调用函数的语句不能作为可执行语句单独出现在PL/SQL块中。如:变量名:=函数名(实际参数1,实际参数2.),程序包包(package)是一个可以将相关对象存储在一起的PL/SQL结构。包包含了两个分离的组成部分:包规范和包体。每个部分都单独被存储在数据字典中。包说明是一个操作接口,对应用来说是可见;包规范是黑盒,对应用来说隐藏了实现细节。除了可以将相关对象作为一组存储在一起以外,包也是十分有用的,它们在依赖性方面的限制比较小的,并且有许多性能上的优点。具有createpackage权限,程序包,CREATEPACKAGE语句来创建包的说明部分:CREATEORREPLACEPACKAGE包名IS|AS公共变量的定义|公共类型的定义|公共出错处理的定义|公共游标的定义|函数说明|过程说明END;/注:无begin,创建包主体的语法,CREATEORREPLACEPACKAGEBODY包名IS|AS私有变量的定义|私有类型的定义|私有出错处理的定义|私有游标的定义|函数定义|过程定义END;/,程序包,调用程序包中的过程.调用程序包中的函数:.,例子,【例】制作sal_package包的说明。生成一个管理雇员薪水的包sal_package,其中包括一个为雇员加薪的过程,降薪的过程,并且在包中还有两个记录所有雇员薪水增加和减少的全局变量。CREATEorreplacePACKAGEsal_packageISPROCEDUREraise_sal(v_empnoemp.empno%TYPE,v_sal_incrementemp.sal%TYPE);PROCEDUREreduce_sal(v_empnoemp.empno%TYPE,v_sal_reduceemp.sal%TYPE);v_raise_salemp.sal%TYPE:=0;v_reduce_salemp.sal%TYPE:=0;END;/,sal_package包的包体。CREATEORREPLACEPACKAGEBODYsal_packageISPROCEDUREraise_sal(v_empnoemp.empno%TYPE,v_sal_incrementemp.sal%TYPE)ISBEGINUPDATEempSETsal=sal+v_sal_incrementWHEREempno=v_empno;v_raise_sal:=v_raise_sal+v_sal_increment;END;,PROCEDUREreduce_sal(v_empnoemp.empno%TYPE,v_sal_reduceemp.sal%TYPE)ISBEGINUPDATEempSETsal=sal-v_sal_reduceWHEREempno=v_empno;v_reduce_sal:=v_reduce_sal+v_sal_reduce;END;END;/,在sqlplus环境执行包,SqlEXECUTEsal_package.raise_sal(7788,1000);,程序包,DROPPACKAGEBODY删除程序包体:DROPPACKAGEBODYpackagebody_name;DROPPACKAGE命令删除程序包的说明部分:DROPPACKAGEpackage_name;,程序包,程序包管理,程序包,添加程序包,程序包,程序包管理查看程序包体,程序包,添加程序包,触发器管理,触发器的基本概念创建及使用触发器,触发器一、触发器的基本概念触发器类似于存储过程和函数,都是有说明部分、语句执行部分和出错处理部分三部分组成的PL/SQL有名块,触发器存储在数据库数据字典中。但是,对于存储过程而言,可以在另一个程序中调用过程,显式地执行一个过程,同时在调用时可以往存储过程传递参数。对于触发器而言,当触发事件发生时隐式地(自动地)执行该触发器,不能在程序中调用触发器,并且触发器不接受参数。,1、触发事件和触发器的功能(1)可以触发触发器的事件包括:在数据库表上执行的INSERT、UPDATE、DELETE操作。(2)使用触发器可以做许多事情,包括:维护不可能在表创建时通过说明性约束进行的复杂的完整性约束限制。通过记录所进行的修改以及谁做了修改等信息对表进行审计。当表被修改的时候,自动给需要执行操作的程序发信号。等等,注:一般情况下,触发器中只能包括select语句和DML语句,不能含有DDL和DCL语句。(静态SQL),2、触发器的组成,3、触发器的类型触发器分语句级触发器和行级触发器两个级别。行级触发器与语句级触发器的区别主要在于其触发的次数不同,如果该DML语句只影响一行,则语句级与行级触发器效果一样。如果该DML语句影响多行,则行级触发器触发的次数比语句级触发器触发的次数多。,例:下列DML语句对语句级触发器和行级触发器效果一样。SQLINSERTINTODEPT(deptno,dname)VALUES(50,EDUCATION);SQLUPDATEDEPTSETLOCMAUIWHEREDEPTNO50;SQLDELETEFROMDEPTWHEREDEPTNO50;例:下列DML语句的行级触发器与语句级触发器效果不同。SQLINSERTINTOEMP(empno,ename)SELECTempno,enameFROMEMP_BACKUP;SQLUPDATEDEPTSETSALSAL*1.1WHEREDEPTNO10;,4、触发器与存储过程的区别,创建及使用触发器,CREATETRIGGER语句来创建触发器:CREATEORREPLACETRIGGERBEFORE|AFTERONFOREACHROWWHEN,2、语句级触发器用CREATETRIGGER语句创建一个语句级触发器,该触发器在一个数据操作语句发生时只触发一次。(1)创建一个语句级触发器的语法CREATEORREPLACETRIGGERtrigger_nameBEFORE|AFTERevent1ORevent2.ONtable_namePL/SQLblock,例:创建一个BEFORE型语句级触发器。限制一周内往EMP表插入数据的时间。CREATEORREPLACETRIGGERsecure_empBEFOREINSERTONempBEGINIF(TO_CHAR(sysdate,DY)IN(SAT,SUN)OR(TO_CHAR(sysdate,HH24)NOTBETWEEN8AND18)THENRAISE_APPLICATION_ERROR(-20500,YOUmayonlyinsertintoEMPduringnormalhours);ENDIF;END;/,(2)使用触发器谓词(INSERTING、UPDATING、DELETING)DML触发器是一个INSERT、UPDATE、DELETE触发器。可以创建一个包含多个触发事件的触发器,在触发器体中使用谓词(INSERTING,UPDATING及DELETING)判断是哪个触发事件触发了触发器,从而把多种触发事件组成一个触发器。,触发器谓词的行为和值,例:对前一例子进行扩展,不但限制插入数据的时间,还限制进行数据修改和删除的时间。CREATEORREPLACETRIGGERsecure_empBEFOREDELETEORINSERTORUPDATEONempBEGINIF(TO_CHAR(sysdate,DYIN(SAT,SUN)OR(TO_NUMBER(sysdate,HH24)NOTBETWEEN8AND18)THENIFDELETINGTHENRAISE_APPLICATION_ERROR(-20502,YoumayonlydeletefromEMPduringnormalhours.);,ELSIFINSERTINGTHENRAISE_APPLICATION_ERROR(-20500,YoumayonlyinsertintoEMPduringmormalhours);ELSETHENRAISE_APPLICATION_ERROR(-20504,YoumayonlyupdateEMPtableduringnormalhours);ENDIF;ENDIF;END;/,3、行级触发器(1)创建行级触发器的语法通过在CREATETRIGGER语句中指定FOREACHROW子句创建一个行级触发器,使其在受到触发事件影响的每一行上都被触发。CREATEORREPLACETRIGGERtrigger_nameBEFORE|AFTERevent1ORevent2.ONtable_nameFOREACHROWWHENrestricting_conditionPL/SQLblock;,例:创建一个行级触发器。将每个用户对数据库EMP表进行数据操纵(插入、更新、删除)的次数记录到audit_table表中。CREATEORREPLACETRIGGERaudit_empAFTERDELETEORINSERTORUPDATEONempFOREACHROWBEGINIFDELETINGTHENUPDATEaudit_tableSETdeldel+lWHEREuser_name=userANDtable_nameEMPANDcolun_nameISNULL;,ELSIFINSERTINGTHENUPDATEaudit_tableSETins=ins+lWHEREuser_name=userANDtable_name=EMPANDcolumn_nameISNULL;EISEUPDATEaudit_tableSETupd=upd+1WHEREuser_name=userANDtable_nameEMPANDcolumn_nameISNULL;ENDIF;END;/,(2)使用行级触发器的标识符:OLD和:NEW,在行级触发器中,在列名前加上:OLD标识符表示该列变化前的值,加上:NEW标识符表示变化后的值。:OLD和:NEW的意义,例:在行级触发器中获取某列的新值和旧值,为EMP表中的所有数据保留一个历史档案CREATEORREPLACETRIGGERaudit_emp_valuesAFTERDELETEORINSERTORUPDATEONempFOREACHROWBEGININSERTINTOaudit_emp(user_name,timestamp,empno,old_ename,new_ename,old_job,new_job,old_sal,new_sal)VALUES(USER,SYSDATE,:old.empno,:old.ename,:new.ename,:old.job,:new.job,:old.sal,:new.sal);END;/,例:在行级触发器加WHEN限制条件。根据销售员工资的改变自动计算销售员的奖金。CREATEORREPLACETRIGGERderive_commBEFOREUPDATEOFsalONempFOREACHROWWHEN(new.jobSALESMAN)BEGIN:m:=:m*(:new.sal:old.sal);END;/,例:对audit_emp_values触发器,可以用下列命令进行测试。(1)首先用CREATETABLE语句建立保留EMP历史档案信息的audit_emp表SQLCREATETABLEaudit_emp(user_namevarchar2(30),timestampdate,empnonumber(4),old_enamevarchar2(12),new_enamevarchar2(12),old_jobvarchar2(12),new_jobvarchar2(12),old_salnumber,new_salnumber);,(2)对EMP表执行INSERT、UPDATE、DELETE操作SQLINSERTINTOemp(empno,ename,job,sal,deptno)VALUES(1111,张三,SALESMAN,3000,20);SQLUPDATEempSETename=李四,sal=5000WHEREempno=1111;SQLDELETEFROMempWHEREempno=1111;(3)查看audit_emp表是否增加了记录以及增加记录的值的变化。SQLSELECT*FROMaudit_emp;,五、触发器的应用,创建数据库触发器,可以大大增强Oracle系统的性能,完成一些Oracle系统本身提供的服务所不能完成的功能。触发器的应用主要是以下几个方面:安全性审计数据完整性参考完整性数据复制,1、安全性在Oracle中通过给用户授权完成对表中数据进行操作的安全性控制。例:使用权限控制安全性。SQLGRANTSELECT,INSERT,UPDATE,DELETEONEMPTOCLERK;但如果希望限制CLERK用户只能在特定时间内访问EMP表,非规定时间内不允许访问,则可以使用数据库触发器,实现进一步的安全性控制。,例:在触发器中控制数据的安全性。限制只允许在某周的特定时间内进行数据操作。CREATEORREPLACETRIGGERsecure_empBEFOREINSERTORUPDATEORDELETEONempBEGINIF(TO_CHAR(sysdate,DY)IN(SAT,SUN)OR(TO_NUMBER(sysdate,HH24)NOTBETWEEN8AND18)THENraise_application_error(-20506,Youmayonlychangedataduringnormalhours.);ENDIF;END;/,2、审计Oracle系统本身提供了审计功能,可以审计用户插入、更新、删除、查询语句、DDL语句的执行次数,也可以审计操作的成功和失败,并把审计情况写入审计表中(数据字典表中)。但不能审计数据操纵时值的变化,。例:利用系统本身提供的审计,审计EMP表上所有成功的数据操作的次数。SQLAUDITINSERT,UPDATE,DELETEONempBYACCESSWHENEVERSUCCESSFUL;,利用触发器可以审计操纵语句所操作的值的变化,可以将值的变化情况写入用户定义的档案表。例:用触发器进行审计。将EMP表上值的变化记录到audit_emp表中。CREATEORREPLACETRIGGERaudit_emp_valuesAFTERDELETEORINSERTORUPDATEONempFOREACHROWBEGININSERTINTOaudit_emp(user_name,timestamp,empno,old_ena

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论