直接上例子:
drop table web_org_oper_history;
create table web_org_oper_history(
autoId number primary key,
c_oper_id varchar2(50) not null,
c_passwd varchar2(32),
oper_date timestamp
);
comment on column web_org_oper_history.c_oper_id is 'ID';
comment on column web_org_oper_history.c_passwd is '密码';
CREATE SEQUENCE seq_trg_oper_autoid;
select * from web_org_oper_history;
---触发器
create or replace trigger web_org_oper_triger
after insert or update or delete on web_org_oper
for each row
declare
pragma AUTONOMOUS_TRANSACTION;
l_found boolean;
code NUMBER;
msg VARCHAR2(500);
begin
if length(:new.c_passwd)>6 then--测试
raise_application_error(-20000, '密码长度超过6字节');
end if;
if inserting and :new.c_oper_id is not null then
insert into web_org_oper_history(autoId,c_oper_id,c_passwd,oper_date)
values(seq_trg_oper_autoid.NEXTVAL,:new.c_oper_id,:new.c_passwd,sysdate);
Dbms_output.put_line('增加操作');
elsif updating and :new.c_passwd is not null then
l_found :=false;
for c1 in(select c_oper_id from web_org_oper_history where c_oper_id=:new.c_oper_id and c_passwd=:old.c_passwd) loop
l_found :=true;
exit;
end loop;
if not l_found then
insert into web_org_oper_history(autoId,c_oper_id,c_passwd,oper_date)
values(seq_trg_oper_autoid.NEXTVAL,:new.c_oper_id,:new.c_passwd,sysdate);
Dbms_output.put_line('增加操作');
else
update web_org_oper_history set c_passwd=:new.c_passwd,oper_date=sysdate where c_oper_id=:new.c_oper_id;
Dbms_output.put_line('更新操作');
/*insert into web_org_oper_history(c_oper_id,c_passwd)
values(:new.c_oper_id,:new.c_passwd); */
end if;
end if;
commit;
/*下面异常捕获 对上面判断不返回到应用程序 注释掉即可返回到应用*/
EXCEPTION
WHEN OTHERS THEN
code := SQLCODE;
msg := substr(SQLERRM, 1, 500);
Dbms_output.put_line(code);
Dbms_output.put_line(msg);
ROLLBACK;
RAISE;
end web_org_oper_triger;
instead of触发器 转自文档:http://blog.sina.com.cn/s/blog_7cc3b8db010113oj.html
下面介绍一种instead of触发器,该触发器主要使用在对视图的更新上,以下是instead of触发器的语法:
CREATE OR REPLACE TRIGGER trigger_name
INSTEAD OF <insert | update | delete> ON view_name
[FOR EACH ROW]
WHEN (condition)
DECLARE
BEGIN
--触发器代码
END;
其他部分语法同前面所述的before和after语法是一样的,唯一不同的是在第二行用上了instead of关键字。对于普通的视图来说,进行insert等操作是被禁止的,因为Oracle无法知道操作的字段具体是哪个表中的字段。但我们可以通过建立instead of触发器,在触发器主体中告诉Oracle应该更新,删除或者修改哪些表的哪部分字段。如:
6,例三:instead of触发器
新建视图
CREATE VIEW employee_salary(employee_id, maxsalary, MONTH, amount) AS
SELECT a.employee_id, a.maxsalary, b.MONTH, b.amount
FROM employment a, salary b
WHERE a.employee_id = b.employee_id
如果执行插入语句
INSERT INTO employee_salary(employee_id, maxsalary, MONTH, amount)
VALUES(10, 100000, '200606', 10000);
系统会报错:
ORA-01779:无法修改与非键值保存表对应的列
我们可以通过建立以下的instead of存储过程,将插入视图的值分别插入到两个表中:
create or replace trigger employee_salary_rii
instead of insert on employee_salary
for each ROW
DECLARE
v_cnt NUMBER;
BEGIN
--检查是否存在该员工信息
SELECT COUNT(*)
INTO v_cnt
FROM employment
WHERE employee_id = :NEW.employee_id;
IF v_cnt = 0 THEN
INSERT INTO employment
(employee_id, maxsalary)
VALUES
(:NEW.employee_id, :NEW.maxsalary);
END IF;
--检查是否存在该员工的工资信息
SELECT COUNT(*)
INTO v_cnt
FROM salary
WHERE employee_id = :NEW.employee_id
AND MONTH = :NEW.MONTH;
IF v_cnt = 0 THEN
INSERT INTO salary
(employee_id, MONTH, amount)
VALUES
(:NEW.employee_id, :NEW.MONTH, :NEW.amount);
END IF;
END employee_salary_rii;
该触发器被建立后,执行上述insert操作,系统就会提示成功插入一条记录。
但需要注意的是,这里的“成功插入一条记录”,只是Oracle并未发现触发器中有异常抛出,而根据insert语句中涉及的记录数作出一个判断。若触发器的主体什么都没有,只是一个空语句,Oracle也会报“成功插入一条记录”。同样道理,即使在触发器主体里往多个表中插入十条记录,Oracle的返回也是“成功插入一条记录”。
行级触发器可以解决大部分的问题,但是如果需要对本表进行扫描检查,比如要检查总的工资是否超限了,用行级触发器是不行的,因为行级触发器主体中不能有涉及到关联表的事务,这时就需要用到语句级触发器。以下是语句级触发器的语法:
CREATE OR REPLACE TRIGGER trigger_name
<before | after | instead of ><insert | update | delete > ON table_name
DECLARE
BEGIN
--触发器主体
END;
从语法定义上来看,行级触发器少了for each row,也不能使用when子句来限定入口条件,其他部分都是一样的,包括insert, update, delete和instead of都可以使用。
7,例四:语句级触发器之一
CREATE OR REPLACE TRIGGER salary_saiu
AFTER INSERT OR UPDATE OF amount ON salary
DECLARE
v_sumsalary NUMBER;
BEGIN
SELECT SUM(amount) INTO v_sumsalary FROM salary;
IF v_sumsalary > 500000 THEN
raise_application_error(-20001, '总工资超过500000');
END IF;
END;
以上代码定义了一个语句级触发器,该触发器检查在insert和update了amount字段后操作后,工资表中所有工资记录累加起来是否超过500000,如果超过则抛出异常。从这个例子可以看出,语句级触发器可以对关联表表进行扫描,扫描得到的结果可以用来作为判断一致性的标志。需要注意的是,在before语句触发器主体和after语句触发器主体中对关联表进行扫描,结果是不一样的。在before语句触发器主体中扫描,扫描结果将不包括新插入和更新的记录,也就是说当以上代码换成 before触发器后,以下语句将不报错:
INSERT INTO salary(employee_id, month, amount) VALUEs(2, '200601', 600000)
这是因为在主体中得到的v_sumsalary并不包括新插入的600000工资。
另外,在语句级触发器中不能使用:new和:old对象,这一点和行级触发器是显著不同的。如果需要检查插入或更新后的记录,可以采用临时表技术。
临时表是一种Oracle数据库对象,其特点是当创建数据的进程结束后,进程所创建的数据也随之清除。进程与进程不可以互相访问同一临时表中对方的数据,而且对临时表进行操作也不产生undo日志,减少了数据库的消耗。具体有关临时表的知识,可以参看有关书籍。
为了在语句级触发器中访问新插入后修改后的记录,可以增加行级触发器,将更新的记录插入临时表中,然后在语句级触发器中扫描临时表,获得修改后的记录。临时表的表结构一般与关联表的结构一致。
8,例五:语句级触发器之二
目的:限制每个员工的总工资不能超过50000,否则停止对该表操作。
创建临时表
create global temporary table SALARY_TMP
(
EMPLOYEE_ID NUMBER,
MONTH VARCHAR2(6),
AMOUNT NUMBER
)
on commit delete rows;
为了把操作记录插入到临时表中,创建行级触发器:
CREATE OR REPLACE TRIGGER salary_raiu
AFTER INSERT OR UPDATE OF amount ON salary
FOR EACH ROW
BEGIN
INSERT INTO salary_tmp(employee_id, month, amount)
VALUES(:NEW.employee_id, :NEW.MONTH, :NEW.amount);
END;
该触发器的作用是把更新后的记录信息插入到临时表中,如果更新了多条记录,则每条记录都会保存在临时表中。
创建语句级触发器:
CREATE OR REPLACE TRIGGER salary_sai
AFTER INSERT OR UPDATE OF amount ON salary
DECLARE
v_sumsalary NUMBER;
BEGIN
FOR cur IN (SELECT * FROM salary_tmp) LOOP
SELECT SUM(amount)
INTO v_sumsalary
FROM salary
WHERE employee_id = cur.employee_id;
IF v_sumsalary > 50000 THEN
raise_application_error(-20002, '员工累计工资超过50000');
END IF;
DELETE FROM salary_tmp;
END LOOP;
END;
该触发器首先用游标从salary_tmp临时表中逐条读取更新或插入的记录,取employee_id,在关联表salary中查找所有相同员工的工资记录,并求和。若某员工工资总和超过50000,则抛出异常。如果检查通过,则清空临时表,避免下次检查相同的记录。
执行以下语句:
INSERT INTO salary(employee_id, month, amount) VALUEs(7, '200601', 20000);
INSERT INTO salary(employee_id, month, amount) VALUEs(7, '200602', 20000);
INSERT INTO salary(employee_id, month, amount) VALUEs(7, '200603', 20000);
在执行第三句时系统报错:
ORA-20002:员工累计工资超过50000
查询salary表,发现前两条记录正常插入了,第三条记录没有插入。
如果系统结构比较复杂,而且触发器的代码比较多,在触发器主体中写过多的代码,对于维护来说是一个困难。这时可以将所有触发器的代码写到同一个包中,不同的触发器代码以不同的存储过程封装,然后触发器主体中调用这部分代码。
9,例六:用包封装触发器代码
目的:改写例五,封装触发器主体代码
创建代码包:
CREATE OR REPLACE PACKAGE BODY salary_trigger_pck IS
PROCEDURE load_salary_tmp(i_employee_id IN NUMBER,
i_month IN VARCHAR2,
i_amount IN NUMBER) IS
BEGIN
INSERT INTO salary_tmp VALUES (i_employee_id, i_month, i_amount);
END load_salary_tmp;
PROCEDURE check_salary IS
v_sumsalary NUMBER;
BEGIN
FOR cur IN (SELECT * FROM salary_tmp) LOOP
SELECT SUM(amount)
INTO v_sumsalary
FROM salary
WHERE employee_id = cur.employee_id;
IF v_sumsalary > 50000 THEN
raise_application_error(-20002, '员工累计工资超过50000');
END IF;
DELETE FROM salary_tmp;
END LOOP;
END check_salary;
END salary_trigger_pck;
包salary_trigger_pck中有两个存储过程,load_salary_tmp用于在行级触发器中调用,往salary_tmp临时表中装载更新或插入记录。而check_salary用于在语句级触发器中检查员工累计工资是否超限。
修改行级触发器和语句级触发器:
CREATE OR REPLACE TRIGGER salary_raiu
AFTER INSERT OR UPDATE OF amount ON salary
FOR EACH ROW
BEGIN
salary_trigger_pck.load_salary_tmp(:NEW.employee_id, :NEW.MONTH, :NEW.amount);
END;
CREATE OR REPLACE TRIGGER salary_sai
AFTER INSERT OR UPDATE OF amount ON salary
BEGIN
salary_trigger_pck.check_salary;
END;
这样主要代码就集中到了salary_trigger_pck中,触发器主体中只实现了一个调用功能。
10,触发器命名规范
为了方便对触发器命名和根据触发器名称了解触发器含义,需要定义触发器的命名规范:
Trigger_name = table_name_trg_<R|S><A|B|I><I|U|D>
触发器名限于30个字符。必须缩写表名,以便附加触发器属性信息。
<R|S>基于行级(row)还是语句级(statement)的触发器
<A|B|I>after, before或者是instead of触发器
<I|U|D>触发事件是insert,update还是delete。如果有多个触发事件则连着写
例如:
Salary_rai salary表的行级after触发器,触发事件是insert
Employee_sbiud employee表的语句级before触发器,触发事件是insert,update和delete
相关推荐
例如,在上面的示例中,我们创建了一个名为tri_tb1的触发器,该触发器在tb1表中插入新记录时执行。触发器的执行顺序是:首先执行INSERT语句,然后执行触发器。 在FOR INSERT触发器中,我们可以访问inserted表,该表...
### Oracle EBS Forms 触发器执行顺序详解 Oracle E-Business Suite (EBS) 是一个集成的企业资源规划 (ERP) 解决方案,它利用了 Oracle 的技术来提供全面的业务流程管理。其中,Oracle Forms 是一个强大的工具,...
在MySQL中,触发器(Trigger)是一种强大的功能,用于在特定的数据操作(如INSERT、UPDATE、DELETE)发生时自动执行预定义的SQL语句,以此来维护数据的完整性和一致性。触发器可以看作是数据库的自动反应机制,无需...
3. 提高效率:触发器可以提高我们处理数据的效率,例如在删除学生的学号时,自动删除借书记录表中的相应记录。 触发器的类型: ---------------- 1. Insert 触发器:在插入数据时触发。 2. Update 触发器:在更新...
### 触发器实现SQL记录知识点详解 #### 一、背景与需求分析 在很多应用场景中,为了确保数据完整性及可追溯性,我们往往需要记录数据表中的历史变更信息,以便于日后审计或数据分析。例如,在银行系统中,对账户...
3. **日志和错误处理**:示例可能演示了如何记录触发器执行的日志信息,以及如何优雅地处理错误,避免阻止其他记录的处理。 4. **最佳实践**:代码可能会展示Apex触发器编写的最佳实践,比如使用静态变量来减少...
Trigger_sc 触发器是在 SC 表中创建的限制更新触发器,当修改 SC 表中一记录的学号时,要检查 S 中是否存在该学号相同的记录,若存在则不许修改,若不在则可以修改。 C. 用 SQL 方式创建触发器 score_sc_tri score...
3. 触发器的创建:使用`CREATE TRIGGER`创建`AFTER UPDATE`触发器,定义触发条件和执行逻辑。 4. 游标的使用:在更新触发器中,利用游标处理批量更新,确保所有受影响的记录都被处理。 5. 触发器测试:通过更新操作...
SQL语句,存储过程,触发器
SQLite触发器是一种特殊的数据库对象,它可以在特定的数据库事件(如删除、插入或更新记录)发生时自动执行一系列预定义的SQL语句。触发器可以帮助开发者实现数据一致性、业务逻辑自动化等功能。 #### 二、SQLite...
其中,触发器(Trigger)是一种非常重要的组件,它可以根据不同的事件来触发相应的操作。 Oracle Form 触发器的执行顺序是指在不同的事件下触发器的执行过程。在本文中,我们将详细介绍 Oracle Form 触发器的执行...
- 例如,创建一个在用户插入新记录时自动设置创建日期的触发器: ```sql CREATE TRIGGER set_create_date BEFORE INSERT ON user_table FOR EACH ROW BEGIN SET NEW.create_time = NOW(); END; ``` 在这个...
触发器(Trigger)是数据库系统中的一个重要概念,它是一种特殊类型的存储过程,其主要功能是在特定的数据库操作(如INSERT、DELETE、UPDATE)发生时自动执行。触发器的执行不依赖于应用程序的直接调用,而是由...
3. **触发器**:最为灵活,可以根据复杂的条件记录所需信息。 #### 实现方案:使用触发器 本文将详细介绍如何使用触发器来监控表中的数据修改操作。此方案的核心在于利用Oracle数据库中的系统视图,如`v$session`、...
`arduino-web-oscilloscope-support-trigger-5d6312.pdf`可能是项目的手册或指南,详细解释了硬件组装、软件配置和触发器设置等步骤。通过阅读这份文档,开发者可以了解到如何构建和配置这个网络示波器,以及如何...
SQLite当前只支持FOR EACH ROW类型的触发器,这意味着触发器中的SQL语句将针对每一行记录执行。可以使用`WHEN`子句来限制触发器只在满足特定条件的行上执行。 在触发器的步骤中,可以使用`NEW.column-name`和`OLD....
- 行级触发器:在对单条记录进行INSERT、UPDATE或DELETE操作时触发,对每条受影响的记录执行一次。 - 语句级触发器:在执行DML语句后触发,无论操作影响多少记录,只执行一次。 2. 触发事件: - INSERT:在插入...
在数据库管理系统中,SQL触发器是一种特殊类型的存储过程,它能够自动响应对特定表的数据修改(如插入、更新或删除记录等)。触发器可以在数据修改之前或之后执行,也可以代替数据修改操作本身。本文将详细介绍SQL...
- **Insert型触发器**:当向表中插入新数据时,触发器会被激活,可用于记录插入前后的状态或执行级联插入等操作。 - **Update型触发器**:在数据更新时触发,可用于验证更新后的数据有效性,或者记录旧值和新值,...