您的位置:首页 > 数据库 > Oracle

Oracle,day9,游标和触发器

2016-12-13 20:16 561 查看
前言:

昨天去中移在线面试了,问的东西很底层,回答的并不好,哎,又没戏了赶脚。。而且还晕车了,昨天什么都没有学,讲道理爱学习的我应该是非常懊恼的,但是为什么心里有一种莫名的快感[爽!],哈哈,不能颓废啊,让我们开始吧!

游标

SQL语言是面向集合的,是对指定列的操作。如果要对列中的指定行进行操作,就必须使用游标。

当在PL/SQL块中执行查询语句(select)和数据操纵语句(DML)时,Oracle会为其分配一个上下文区(ContextArea),上下文区就是用来存放查询结果的。

游标是指向上下文区的指针,最初指向的是所有行的最上面,它为应用提供了一种对具有多行数据查询结果集中的每一行数据分别进行单独处理的方法。游标指向谁就是取哪一行记录。

游标主要就是用于处理多行的。

游标的种类

显式游标

为了处理SELECT语句返回的多行数据,开发人员可以使用显式游标。显式游标主要用于处理SELECT语句返回的多行数据。

显式游标需要我们为其定义,步骤如下:

1.定义游标

cursor cursor_name is select_statement;


上述语法中,cursor name用于指定游标名称,select_statement用于指定游标对应的SELECT语句。


2.打开游标

open cursor_name;


3.提取数据

fetch cursor_name into variable1,variable2,...;

fetch cursor_name bulk collect into collect1...;


在打开游标之后,SELECT语句的结果被临时存放在游标结果集中。为了处理结果集合中的数据,需要使用FETCH语句提取游标数据。在Oracle 9i之前,使用FETCH语句一次只能提取一行数据。从Oracle 9i开始,通过使用FETCH…BULK COLLECT INTO语句,一次可以提取多行数据。

上述语法中,variablel,variable2,…用于指定接收游标数据的变量,collectl,collect2,…用于指定接收游标结果的集合变量。


4.关闭游标

close cursor_name;


显式游标属性

在实际应用中,我们需要对游标进行判断操作,显式游标属性用于返回显式游标的执行信息,包括%ISOPEN、%FOUND、%NOTFOUND以及%ROWCOUNT等属性。当使用显式游标属性时,必须在显式游标属性之前添加显式游标名作为前缀,其格式为:

游标名%属性名


%isopen:用于确定游标是否已经打开。如果游标已经打开,则返回true;否则返回false。

%found:检查是否从结果集中提取到数据。如果提取到数据,则返回值为true;否则返回false。

%notfound:与%found属性相反。没有提取到数据返回true;提取到了返回false。

%rowcount:返回到当前行为止已经提取到的实际行数。

应用示例:

根据条件查询并输出部门信息。

declare
v_dept dept%rowtype;
cursor dept_cursor is select * from dept where deptno>10;
--定义游标
begin
open dept_cursor; --打开游标
loop  --循环提取游标中的数据
fetch dept_cursor into v_dept;  --提取数据
exit when dept_cursor%notfound; --判断条件,退出循环
dbms_output.put_line('编号:'||v_dept.deptno||'+'||'部门名:'||v_dept.dname||'+'||'地址:'||v_dept.loc);
end loop;
close dept_cursor;  --关闭游标
end;


结果:

匿名块已完成
编号:80+部门名:产品部+地址:深圳
编号:50+部门名:研发部+地址:北京
编号:60+部门名:测试部+地址:上海
编号:70+部门名:实施部+地址:杭州
编号:20+部门名:RESEARCH+地址:DALLAS
编号:30+部门名:SALES+地址:CHICAGO
编号:40+部门名:OPERATIONS+地址:BOSTON


下面也是一个示例,修改员工的奖金,奖金1000以上的加奖金的10%,0<奖金<1000的涨为1000,没有奖金的涨为工资的10%;

declare
v_emp_row emp%rowtype;
cursor emp_cursor is select * from emp;
begin
open emp_cursor;
loop
fetch emp_cursor into v_emp_row;
exit when emp_cursor%notfound;
if nvl(v_emp_row.comm,0)=0 then
update emp set comm=sal*0.1;
elsif nvl(v_emp_row.comm,0)>0 and nvl(v_emp_row.comm,0)<1000 then
update emp set comm=1000;
else
update emp set comm=comm*1.1;
end if;
end loop;
close emp_cursor;
end;


FETCH…INTO语句每次只能处理一行数据,为了处理结果集中的多行数据,必须使用循环语句进行处理。

我也不知道哪里错了,总之查询结果出来后,所有奖金都变成了工资的10%,可能是逻辑错误,但是如果给update语句也加上where判断,那岂不是违背了游标的本意,搞不懂,感觉也不是逻辑错误啊~~


fetch …bulk:

declare
type dept_table_type
is table of dept%rowtype
index by binary_integer;
cursor dept_cursor is select * from dept;
v_dept_table dept_table_type;
begin
open dept_cursor;
fetch dept_cursor bulk collect into v_dept_table;
close dept_cursor;
dbms_output.put_line('编号      '||'部门名     '||'地址      ');
for i in v_dept_table.first..v_dept_table.last loop
dbms_output.put_line(v_dept_table(i).deptno||'    '||v_dept_table(i).dname||'   '||v_dept_table(i).loc);
end loop;
end;


从Oracle 9i开始,通过使用FETCH…BULK COLLECT INTO语句,可以一次性提取结果集中的所有数据。


参数游标

其实带参游标就是加个括号,括号里面协商参数就行了。

示例:

declare
cursor cursor_getEmpByDno(dno number) is  --定义游标参数名及类型
select * from emp where deptno=dno;   --把参数作为条件
v_emp_row emp%rowtype;
begin
open cursor_getEmpByDno(20);    --打开游标时传递参数
loop
fetch cursor_getEmpByDno into v_emp_row;
exit when cursor_getEmpByDno%notfound;
dbms_output.put_line('编号:'||v_emp_row.empno||'+姓名:'||v_emp_row.ename);
end loop;
close cursor_getEmpByDno;
exception
when no_data_found then
dbms_output.put_line('没有该部门');
end;


Tips: 在定义存放v_dept_row的时候,我选择的是和表emp行的类型一样,但是写完发现视频定义的是和游标的行类型一样,也就是这样定义

v_emp_row cursor_getEmpByDno%rowtype;


这样定义也可以执行,学到了。

游标for循环

使用游标for循环时,oracle隐含有打开游标,提取数据并关闭游标这些操作。不需要自己再敲代码。连提取数据都不用了!好省事啊,哈哈哈哈哈哈!

示例:

获取每个部门的名称

declare
cursor dept_cursor is select * from dept;
begin
for dept_row in dept_cursor loop
dbms_output.put_line('第'||dept_cursor%rowcount||'个部门,部门名:'||dept_row.dname);
end loop;
end;


Tips: dept_row只是个人定义的一个变量,方便我们可以取得每行数据,这个变量可以随便取名,你可以叫a,也可以叫b。如果是有参游标,记得在for循环的时候写游标名的后面加上括号参数!

游标变量

当使用显式游标时,需要在定义部分指定其所对应的静态select语句;而当使用游标变量时,开发人员可以在打开游标变量时,指定其所对应的select语句。开发人员可以在应用中直接使用PL/SQL游标变量。在PL/SQL块中使用游标变量包括定义游标变量、打开游标、提取游标数据、关闭游标四个阶段,具体如下。

1.定义REF CURSOR类型和游标变量

为了在PL/SQL块中定义游标变量,必须首先定义ref cursor类型,然后才能定义游标变量。

语法:

type ref_type_name is ref cursor;
cursor_variable ref_type_name;


上述语法中,ref_type_name用于指定自定义类型名,变量名。另外,不能在包内定义游标变量。cursor variable用于指定游标。


示例:

显示部门编号为10的雇员名

declare
type emp_cursor_type is ref cursor;   --定义游标类型
emp_cursor emp_cursor_type;   --定义游标变量
v_emp_row emp%rowtype;
begin
open emp_cursor for
select * from emp where deptno=10;
loop
fetch emp_cursor into v_emp_row;
exit when emp_cursor%notfound;
dbms_output.put_line('第'||emp_cursor%rowcount||'个员工,姓名为:'||v_emp_row.ename);
end loop;
close emp_cursor;
end;


隐式游标

当执行一条DML语句或select…into语句时,都会创建一个隐含游标。

1.隐含游标的名称是SQL,不能对SQL游标显式执行open、fetch和close语句。

2.oracle隐式的打开、提取,并总是自动的关闭SQL游标。

3.隐含游标属性:

SQL%found;

SQL%notfound;

SQL%rowcount;

SQL%isopen;

隐含游标由PL/SQL控制。当执行一条DML语句或者SELECT…INTO语句时,都会创建一个隐含游标。隐含游标的名称是SQL,不能对SQL游标显式地执行OPEN、FETCH和CLOSE语句。Oracle隐式地打开、提取,并总是自动地关闭SQL游标。隐含游标属性包括SQL%FOUND、SQL%NOTFOUND、SQL%ROWCOUNT、SQL%ISOPEN等。

示例:

declare
v_empno emp.empno%type:=7777;
begin
delete from emp where empno=v_empno;
if sql%found then   --判断有没有受影响的行数
dbms_output.put_line('存在该员工,已删除');
else
dbms_output.put_line('不存在该员工');
end if;
end;


触发器

触发器是许多关系数据库系统都提供的一项技术。在ORACLE系统里,触发器类似过程和函数,都有声明,执行和异常处理过程的PL/SQL块。

触发器是指隐含执行的存储过程,它可以使用PL/SQL进行开发。

当发生特定事件(如修改表、创建对象、登录到数据库)时,oracle会自动执行触发器的相应代码。

触发器相当于一个看门狗,他主要就是监听数据库的一些操作,并作出相应的处理。

触发器类型

触发器在数据库里以独立的对象存储,它与存储过程和函数不同的是,存储过程与函数需要用户显示调用才执行,而触发器是由一个事件来启动运行。即触发器是当某个事件发生时自动地隐式运行。并且,触发器不能接收参数。所以运行触发器就叫触发或点火(firing)。ORACLE事件指的是对数据库的表进行的INSERT、UPDATE及DELETE操作或对视图进行类似的操作。ORACLE将触发器的功能扩展到了ORACLE系统事件的发生,如数据库的启动与关闭等,也会触发触发器。所以触发器常用来完成由数据库的完整性约束难以完成的复杂业务规则的约束,或用来监视对数据库的各种操作,实现审计的功能。

1.DML触发器

在对数据库表进行DML操作时触发,并且可以对每行或者语句操作上进行触发。


2.替代触发器

是oracle8专门为进行视图操作的一种触发器。由于在ORACLE里,不能直接对由两个以上的表建立的视图进行操作。所以给出了替代触发器。它就是ORACLE专门为进行视图操作的一种处理方法。
视图就是对基表的一个图形表现,是基于数据库表的,但是我们对视图的操作并不影响到表内的数据,替代触发器就是我们在对视图进行操作的时候,表内的数据也会有所变化。


3.系统触发器

对数据库系统事件进行触发,如启动、关闭等。比如,我们可以对哪个用户启动了数据库,修改了数据库,关闭了数据库这些信息创建一个日志表,写一个触发器使得在对数据库系统操作的同时就能把这些信息记录进日志表。


触发器组成

1.触发事件

DML或DDL语句。
引起触发器被触发的事件。
例如:DML语句(INSERT,UPDATE,DELETE语句对表或视图执行数据处理操作;select不可以触发触发器,但是select...into可以)、DDL语句(如CREATE、ALTER、DROP语句在数据库中创建、修改、删除模式对象)、数据库系统事件(如系统启动或退出、异常错误)、用户事件(如登录或退出数据库)。


2.触发时间

是在触发事件之前(before)还是之后(after)触发。


3.触发操作

使用PL/SQL块进行相应的数据库操作。
即该TRIGGER被触发之后的目的和意图,正是触发器本身要做的事情。


4.触发对象

表、视图、模式、数据库。
只有在这些对象上发生了符合触发条件的触发事件,才会执行触发操作。


5.触发频率

触发器内定义的动作被执行的次数。
即语句级(STATEMENT)触发器和行级(ROW)触发器。

语句级(STATEMENT)触发器:是指当某触发事件发生时,该触发器只执行一次;
行(ROW)触发器:是指当某触发事件发生时,对受到该操作影响的每一行数据,触发器都单独执行一次。


6.触发条件

由WHEN子句指定一个逻辑表达式。只有当该表达式的值为TRUE时,遇到触发事件才会自动执行触发器,使其执行触发操作。


编写触发器时,需要注意以下几点

1.触发器不接受参数。

2.一个表上最多可有12个触发器,但同一时间、同一事件、同一类型的触发器只能有一个。并各触发器之间不能有矛盾。

3.在一个表上的触发器越多,对在该表上的DML操作的性能影响就越大。

4.触发器最大为32KB。若确实需要,可以先建立过程,然后在触发器中用CALL语句进行调用。

5.在触发器的执行部分只能用DML语句(INSERT、UPDATE、DELETE,不包含select!),不能使用DDL语句(CREATE、ALTER、DROP)。

6.触发器中不能包含事务控制语句(COMMIT,ROLLBACK,SAVEPOINT)。因为触发器是触发语句的一部分,触发语句被提交、回退时,触发器也被提交、回退了。在触发器主体中调用的任何过程、函数,都不能使用事务控制语句。在触发器主体中不能声明任何Long和blob变量。新值new和旧值old也不能向表中的任何long和blob列。

7.不同类型的触发器(如DML触发器、INSTEAD OF触发器、系统触发器)的语法格式和作用有较大区别。

语句触发器

语句触发器是指当执行DML语句时被隐含执行的触发器。

如果在表上针对某种DML操作创建了语句触发器,则当执行DML操作时会自动地执行触发器的相应代码。

为了审计DML操作,或者确保DML操作安全执行时,可以使用语句触发器。

语法:

CREATE [OR REPLACE] TRIGGER trigger_name
{BEFORE | AFTER }
{INSERT | DELETE | UPDATE [OF column [, column ...] ] }
[OR {INSERT  |  DELETE  | UPDATE  [OF column [,  column ...] ] } ...]
ON  [ schema . ] table_name  |   [ schema . ] view_name
[REFERENCING {OLD [AS] old | NEW [AS] new} ]
[FOR EACH ROW ]
[WHEN condition]
PL/SQL_BLOCK | CALL procedure_name;


FOR EACH ROW选项说明触发器为行触发器。行触发器和语句触发器的区别表现在:行触发器要求当一个DML语句操做影响数据库中的多行数据时,对于其中的每个数据行,只要它们符合触发约束条件,均激活一次触发器;而语句触发器将整个语句操作作为触发事件,当它符合约束条件时,激活一次触发器。当省略FOR EACH ROW选项时,BEFORE和AFTER触发器为语句触发器,而INSTEAD OF触发器则只能为行触发器。


每张表最多可建立12种类型的触发器,它们是:

BEFORE INSERT

BEFORE INSERT FOR

AFTER INSERT

EACH ROW

AFTER INSERT FOR EACH ROW

BEFORE UPDATE

BEFORE UPDATE FOR EACH ROW

AFTER UPDATE

AFTER UPDATE FOR EACH ROW

BEFORE DELETE

BEFORE DELETE FOR EACH ROW

AFTER DELETE

AFTER DELETE FOR EACH ROW

触发器触发顺序

1.执行BEFORE语句级触发器

2.对于受语句影响的每一行:

执行BEFORE行级触发器

执行DML语句

执行AFTER行级触发器

3.执行AFTER语句级触发器

创建触发器

建立一个触发器,当职工表emp表被删除一行记录时,把被删除记录写到职工表删除日志表中去。

首先,创建一个职工删除日志表

create table emp_his as select * from emp where 1=2;


这里又学了一招,创建一个表然后写上as select * from emp where 1=2这样一句话。1什么时候都不等于2,所以这样一句话的意思就是,创建一个表和另一个表的结构一样,不复制他的数据。如果数据也要复制,那么就把where 1=2去掉就可以了。


好的,创建触发器吧!

create or replace trigger tr_del_emp
before delete   --指定触发时机为删除操作前触发
on c##scott.emp
for each row    --说明创建的是行级触发器
begin
--将修改前数据插入到日志记录表emp_hie,以供监督使用。
insert into emp_his(deptno,empno,ename,job,mgr,hiredate,sal,comm)
values(:old.deptno,:old.empno,:old.ename,:old.job,:old.mgr,:old.hiredate,:old.sal,:old.comm);
end;


不知道为嘛,老师写的触发器出了问题,结果自己就好了,不懂,反正我是一次就成了~天才!

创建before语句触发器

如果指定了before关键字,且没有加for each row,那么就是before语句触发器,就表示执行DML操作之前触发触发器。

示例:

禁止在周四和周六修改员工信息

create or replace trigger tri_no_sun
before
insert or update or delete
on emp
begin
if to_char(sysdate,'day')in('星期四','星期六') then
raise_application_error(-20000,'dont delete on Wednesday or Saturday');
end if;
end;


使用条件谓词

当在触发器中同时包含多个触发事件时,为了在触发器代码中区分具体的触发事件,可以使用以下三个条件谓词:

inserting:当触发事件为insert操作时,该条件谓词返回值为true,否则返回false。
updating:当触发事件为update操作时,....
deleting:当触发事件为delete操作时,....


示例:

(把操作区分开对待。。麻烦)

create or replace trigger tri_option_dept
before
insert or update or delete
on dept
begin
if to_char(sysdate,'day')in('星期三','周期六') then
case
when inserting then
raise_application_error(-20001,'周三或周六不能录入员工信息');
when updating then
raise_application_error(-20002,'周三或周六不能更新员工信息');
when deleting then
raise_application_error(-20003,'周三或周六不能删除员工信息');
end case;
end if;
end;


Tips: 也可以使用“updating(’列名’)”的语法进一步判断某个列是否被更新了。例如,以下代码表示如果emp表的sal列更新了,则执行某种处理:

if updating('sal') then


行级触发器

关于:old和:new这个系统自带的变量,这两个变量就是我们对某一行进行修改的时候产生的新的行数据和老的行数据,如果要想用到这两个变量,则需要在定义的时候加上update/insert/delete of [列名],[列名]…其实不能用delete,都delete了,哪还有new。。。

for each row;

:old——修改前的该行记录;

:new——修改后的该行记录;

示例:

如果修改的是部门编号为30的员工工资,则工资不能降低。

create or replace trigger tri_update_sal
before update of sal,comm
or delete on emp
for each row           --行级触发器
when(old.deptno=30)    --判定条件,部门编号为30
begin
case
when updating('sal') then
if :new.sal<:old.sal then
raise_application_error(-20004,'部门30的员工工资不可降低');
end if;
when updating('comm') then
if :new.comm<:old.comm then
raise_application_error(-20005,'部门30的员工奖金不可降低');
end if;
when deleting then
raise_application_error(-20006,'不能删除部门30的员工信息');
end case;
end;


创建after语句触发器

如果指定了after关键字,则表示在执行DML操作之后触发触发器。

利用行触发器实现级联更新。在修改了主表dept中的deptno后(after),级联的、自动的更新子表emp中原来在该部门的员工的deptno。

示例:

create or replace trigger tri_casupdate
after update of deptno
on dept
for each row
begin
dbms_output.put_line('旧部门编号为:'||:old.deptno);
dbms_output.put_line('新部门编号为:'||:new.deptno);
update emp set deptno = :new.deptno where deptno = :old.deptno;
end;


Tips: 这里创建触发器没有出错,提示已编译,但是在更新dept表的deptno的时候却出了错,提示触发器无效且未通过重新验证。希望明天可以解决。。

Tips2: 触发器可以禁用也可以重新启用,代码如下:

alter trigger [trigger_name] disable;  --禁用
alter trigger [trigger_name] enable;   --启用


after触发器多用于级联更新,修改主表后再修改子表的功能。

创建替代触发器

替代触发器只可用于视图,视图也只能创建替代触发器,一对一关系哦~!

为了在不能执行DML操作的复杂视图上执行DML操作,必须基于视图创建instead of 触发器。

其实替代触发器的意思就是,把对视图的操作替换成了对表的操作。

1.只能被创建在视图上,并且该视图没有指定WITH CHECK OPTION选项。
2.不能指定BEFORE或AFTER选项。
3.FOR EACH ROW子可是可选的,即INSTEAD OF触发器只能在行级上触发、或只能是行级触发器,没有必要指定。
4.没有必要在针对一个表的视图上创建INSTEAD OF触发器,只要创建DML触发器就可以了。


创建instead of 触发器时需要注意以下几点:

1.instead of 选项只适用于视图;

2.当基于视图创建触发器时,不能指定before和after选项;

3.当创建instead of 触发器时,必须指定for each row选项;

4.只能在视图上创建instead of 触发器,而不能创建其他类型的触发器。

语法:

CREATE   [OR  RE PLACE]  TRIGGER  trigger_name
INSTEAD OF
{INSERT |  DELETE | UPDATE  [OF column[,column…]])
[OR {INSERT  |  DELETE  |  UPDATE [OF column  [,  column…]]}...]
ON[schema.]view  name--只能定义在视图上
[REFERENCING {OLD [AS] old | NEW [AS] new | PARENT as parent}]
[FOR EACH ROW]--因为INSTEAD OF触发器只能在行级上触发,所以没有必要指定
[WHEN condition]
PL/SQL_block | CALL procedure_name;


示例:

首先创建一个视图:

create or replace view emp_view as
select deptno,count(*) total_employer,sum(sal) total_sal
from c##scott.emp group by deptno;


这时候我们select * from emp_view;显示的数据是每个部门的信息,一个部门一行,信息有:部门编号、总员工数、总工资数。这时要想删除视图里的一行数据,会提示‘此视图的数据操纵操作非法’,禁止我们删除,这时候我们就需要一个替代触发器。


PS: 在创建视图的时候,提示我没有权限创建,于是我又加了这样一行代码,才可以创建视图:grant create view to c##scott;

创建替代触发器:

create or replace trigger tri_emp_del
instead of delete on emp_view for each row
begin
delete from emp where deptno=:old.deptno;
end tri_emp_del;


这时候就可以删除了,然后我们再去看emp表,emp中原部门号为10的员工已被删除掉。

创建系统触发器

ORACLE 11G提供的系统事件触发器可以在DDL或数据库系统上被触发。DDL指的是数据定义语言,如CREATE、ALTER及DROP等。而数据库系统事件包括数据库服务器的启动或关闭,用户的登录与退出、数据库服务错误等。

语法:

create or replace trigger [schema.]trigger_name
[before|after]
{ddl_event_list|database_event_list}
on {database|[schema.]schema}
[when condition]
PL/SQL_block|call procedure_name;


其中:ddl_event_list: 一个或多个DDL事件,事件间用OR分开;

database_event_list: 一个或多个数据库事件,事件间用OR分开;

系统事件触发器既可以建立在一个模式上,又可以建立在整个数据库上。当建立在模式(SCHEMA)之上时,只有模式所指定用户的DDL操作和它们所导致的错误才激活触发器,默认时为当前用户模式。当建立在数据库(DATABASE)之上时,该数据库所有用户的DDL操作和他们所导致的错误,以及数据库的启动和关闭均可激活触发器。要在数据库之上建立触发器时,要求用户具有ADMINISTER DATABASE TRIGGER权限。

表:系统触发器的种类和事件出现的时机



创建系统事件触发器时,应用开发人员经常需要使用事件属性函数。

事件属性函数表:

ora_client_ip_address

返回客户端的IP地址

ora_database_name

返回当前数据库名

ora_dict_obj_name

返回DDL操作所对应的数据库对象名

ora_dict_obj_owner

返回DDL操作所对应的对象的所有者名

ora_dict_obj_type

返回DDL操作所对应的数据库对象的类型

ora_instance_num

返回例程号

ora_is_alter_column(column_name IN VARCHAR2)

检测特定列是否被修改

ora_is_drop_column(column_name IN VARCHAR2)

检测特定列是否被删除

ora_login_user

返回登录用户名

ora_sysevent

返回触发触发器的系统事件名

示例:

我们首先创建一个表,用来记录我们的DDL操作日志

create table ddl_event
( crt_date timestamp primary key,
event_name VARCHAR2(20),
user_name VARCHAR2(10),
obj_type VARCHAR2(20),
obj_name VARCHAR2(20));


OK,表已建好,我们写一个触发器,用来记录我们的DDL操作日志

create or replace trigger tr_ddl
after ddl on schema
begin
insert into ddl_event values(systimestamp,ora_sysevent,ora_login_user,ora_dict_obj_type,ora_dict_obj_name);
end tr_ddl;


之后我们删除一个表试试看

drop table tb_test;


再去看我们创建的日志表ddl_evevt,就多了一行数据

crt_date | event_name | user_name | obj_type | obj_name

18-12月-16 02.20.51.289000000 下午 | DROP | C##SCOTT | TABLE | TB_TEST

示例:

创建登录、退出触发器

首先创建一个记录数据库事件的表

create table log_event
( user_name varchar2(10),
address varchar2(20),
logon_date timestamp,
logoff_date timestamp);


好了,接下来创建登录触发器

create or replace trigger tr_logon
after logon on database
begin
insert into log_event(user_name,address,logon_date) values(ora_login_user,ora_client_ip_address,systimestamp);
end tr_logon;


创建退出触发器

create or replace trigger tr_logoff
before logoff on database
begin
insert into log_event(user_name,address,logoff_date) values(ora_login_user,ora_client_ip_address,systimestamp);
end tr_logoff;


就是这样,其实,上面的登录,退出触发器我都没有创建成功,因为权限不足,我就懒得再换了,总之系统触发器就是这样用的,OK
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  oracle
相关文章推荐