Oracle入门(十四.22)之创建DDL和数据库事件触发器
一、什么是DDL和数据库事件触发器?
DDL语句触发DDL触发器:CREATE,ALTER或DROP。
数据库事件触发器由数据库中的非SQL事件触发,例如:
•用户连接到数据库或与数据库断开连接。
•DBA启动或关闭数据库。
•用户会话中引发了特定的异常。
(1)在DDL语句中创建触发器语法
•ON DATABASE在数据库中的所有模式上触发DDL
•ON SCHEMA仅针对您自己的模式中的对象触发DDL
CREATE [OR REPLACE] TRIGGER trigger_name
Timing
[ddl_event1 [OR ddl_event2 OR ...]]
ON {DATABASE|SCHEMA}
trigger_body
(2)DDL触发器的示例
每次在模式中创建新的数据库对象时,都希望写入日志记录:
CREATE OR REPLACE TRIGGER log_create_trigg
AFTER CREATE ON SCHEMA
BEGININSERT INTO log_tableVALUES (USER, SYSDATE);
END;
只要有任何(类型)的对象被创建,触发器就会触发。 您不能创建引用特定数据库对象的DDL触发器。
(3)DDL触发器的第二个例子
防止从模式中删除任何对象。
CREATE OR REPLACE TRIGGER prevent_drop_trigg
BEFORE DROP ON SCHEMA
BEGINRAISE_APPLICATION_ERROR (-20203, 'Attempted drop – failed');
END;
只要有任何(类型)的对象被删除,触发器就会触发。 同样,您不能创建引用特定数据库对象的DDL触发器。
(4)在数据库事件语法上创建触发器
•ON DATABASE触发数据库中所有会话的事件触发器。
•ON SCHEMA仅为您自己的会话触发触发器。
CREATE [OR REPLACE] TRIGGER trigger_name
timing
[database_event1 [OR database_event2 OR ...]]
ON {DATABASE|SCHEMA}
trigger_body
二、LOGON、LOGOFF和SERVERERROR
示例1:LOGON和LOGOFF触发器
CREATE OR REPLACE TRIGGER logon_trig
AFTER LOGON ON SCHEMA
BEGIN
INSERT INTO log_trig_table(user_id,log_date,action)VALUES (USER, SYSDATE, 'Logging on');
END;
CREATE OR REPLACE TRIGGER logoff_trig
BEFORE LOGOFF ON SCHEMA
BEGIN
INSERT INTO log_trig_table(user_id,log_date,action)VALUES (USER, SYSDATE, 'Logging off');
END;
示例2:SERVERERROR触发器
想保留会话中发生的任何ORA-00942错误的日志:
CREATE OR REPLACE TRIGGER servererror_trig
AFTER SERVERERROR ON SCHEMA
BEGIN
IF (IS_SERVERERROR (942)) THENINSERT INTO error_log_table ...
END IF;
END;
三、触发器中的CALL语句
没有结束;语句,并且在CALL语句结尾处没有分号。
语法:
CREATE [OR REPLACE] TRIGGER trigger_name
timing
event1 [OR event2 OR event3]
ON table_name
[REFERENCING OLD AS old | NEW AS new]
[FOR EACH ROW]
[WHEN condition]
CALL procedure_name
例子:
CREATE OR REPLACE TRIGGER log_employee
BEFORE INSERT ON EMPLOYEESCALL log_execution
四、突变表和行触发器
突变表是一个当前正在由DML语句修改的表。
行触发器不能从变异表中选择,因为它会看到不一致的数据集(当触发器尝试读取数据时,表中的数据将会改变)。 但是,如果需要,行触发器可以从不同的表中进行选择。
此限制不适用于DML语句触发器,仅适用于DML行触发器。
突变表:例子
CREATE OR REPLACE TRIGGER check_salaryBEFORE INSERT OR UPDATE OF salary, job_id ON employeesFOR EACH ROW
DECLAREv_minsalary employees.salary%TYPE;v_maxsalary employees.salary%TYPE;
BEGINSELECT MIN(salary), MAX(salary)INTO v_minsalary, v_maxsalaryFROM employeesWHERE job_id = :NEW.job_id;IF :NEW.salary < v_minsalary OR:NEW.salary > v_maxsalary THENRAISE_APPLICATION_ERROR(-20505,'Out of range');END IF;
END;
UPDATE employees
SET salary = 3400
WHERE last_name = 'Davies';
出错:
ORA-04091: table USVA_TEST_SQL01_T01_EMPLOYEES is mutating,
trigger/function may not
see it
ORA-06512: at “USVA_TEST_SQL01_T01.CHECK_SALARY”, line 5
ORA-04088: error during execution of trigger
‘USVA_TEST_SQL01_T01.CHECK_SALARY’
3. WHERE last_name – ‘Davies’;
五、触发器的更多可能用途
不应该创建触发器来执行某些可以通过其他方式轻松完成的操作,例如通过检查约束或适当的对象权限。 但是有时你必须创建一个触发器,因为没有其他方法可以做需要的事情。
以下示例只显示了必须创建触发器的三种情况。 还有更多!
(1)第一个例子
数据库安全性(谁可以做什么)通常由系统和对象权限控制。 例如,用户SCOTT需要更新EMPLOYEES行:
GRANT UPDATE ON employees TO scott;
但是,SCOTT被允许这样做时,单凭权限无法控制。 为此,我们需要一个触发器:
CREATE OR REPLACE TRIGGER weekdays_empBEFORE UPDATE ON employees
BEGIN
IF (TO_CHAR (SYSDATE, 'DY') IN ('SAT','SUN')) THENRAISE_APPLICATION_ERROR(-20506,'You may only change data during normal business hours.');
END IF;
END;
(2)第二个例子
数据库完整性(允许DML)通常由约束条件控制。 例如,每个员工的工资必须至少为500美元:
ALTER TABLE employees ADD CONSTRAINT ck_salary CHECK (salary >= 500);
如果一条业务规则指出员工的薪水可以提高但不降低,这个限制并不能阻止员工的薪水从700美元降低到600美元。 为此,我们需要一个行触发器。此代码显示在下一张幻灯片中。
现在我们不再需要约束了。
CREATE OR REPLACE TRIGGER check_salaryBEFORE UPDATE OF salary ON employeesFOR EACH ROWWHEN (NEW.salary < OLD.salaryOR NEW.salary < 500)
BEGINRAISE_APPLICATION_ERROR (-20508,'Do not decrease salary.');
END;
(3)第三个例子
您需要创建一个显示部门总工资单的报表。 你可以声明和使用这个游标:
...
CURSOR tot_sals ISSELECT SUM(salary)FROM employeesWHERE department_id = p_dept_id;
...
但是,如果在一个大型组织中,该部门有10,000名员工呢? 从EMPLOYEES表中抽取10,000行可能太慢。 下面展示了一个更快的方法来做到这一点。
首先,我们在DEPARTMENTS表中添加一个新列以存储每个部门的总工资单:
ALTER TABLE DEPARTMENTS ADD (total_salary NUMBER(12,2));
接下来,只填写当前总工资单的这一栏:
UPDATE departments dSET total_salary = (SELECT SUM(salary) FROM employeesWHERE department_id = d.department_id);
现在,我们必须在更改工资时保持这一新列。 这是通过使用DML行触发器完成的。
CREATE OR REPLACE PROCEDURE increment_salary(p_id IN NUMBER, p_new_sal IN NUMBER) IS
BEGINUPDATE departmentsSET total_salary = total_salary + NVL(p_new_sal,0)WHERE department_id = p_id;
END increment_salary;
CREATE OR REPLACE TRIGGER compute_salary
AFTER INSERT OR UPDATE OF salary OR DELETE
ON employees FOR EACH ROW
BEGIN
IF DELETING THEN increment_salary(:OLD.department_id,(:OLD.salary * -1));
ELSIF UPDATING THEN increment_salary(:NEW.department_id,(:NEW.salary - :OLD.salary));
ELSE increment_salary(:NEW.department_id,:NEW.salary);
END IF;
END;
Oracle入门(十四.22)之创建DDL和数据库事件触发器相关推荐
- java怎样用类模板创建对象_java入门(十四) | 面向对象(OOP)之类和对象
上一期是变量,在java中变量总是无处不在,而变量其意就是可以改变的数,在一般情况下我们可以以变量类型,变量名,变量值来描述它 这一期是给面向对象(OOP)开了一个头,对他的概念,三大特征有了一个基础 ...
- Node学习十四 —— 使用node创建HTTP请求
创建HTTP连接 Node擅长处理I/O操作,所以它不仅合适提供HTTP服务,也适合使用这些服务.接下来你将学习使用http模块和第三方模块执行和控制http请求. 在HTTP协议中,有两个重要的属性 ...
- [unreal4入门系列之十四] 在UE4中添加碰撞触发事件
一.在HUD中显示消息 1) 在MyHUD.h中定义一个结构来表示我们的消息: #pragma once #include "GameFramework/HUD.h" #inclu ...
- Oracle入门(四)之查询基本信息
一.查询基本信息 (1) 查询实例服务 SQL> show parameter instance name (2)查询数据库名字 SQL> show parameter db_name; ...
- Helm 3 完整教程(二十四):创建和使用子 chart
推荐阅读 Helm3(K8S 资源对象管理工具)视频教程:https://edu.csdn.net/course/detail/32506 Helm3(K8S 资源对象管理工具)博客专栏:https: ...
- Oracle笔记 十四、查询XML操作、操作系统文件
--1.随机数 select dbms_random.value from dual; select mod(dbms_random.random, 10) from dual; --0-9随机数 s ...
- slam入门——十四讲笔记(一)
文章目录 第1讲 预备知识 第1部分 数学基础 第2讲 初识SLAM 2.1 引子:小萝卜的例子 2.2 经典视觉SLAM框架 2.3 SLAM问题的数学表述 2.4 实践:编程基础 1. 安装Lin ...
- Oracle资源管理器(二)-- 创建和使用数据库资源计划
(参考 http://blog.csdn.net/mrluoe/article/details/7969436 -- 整理并实践通过) 第1步,创建3个用户 SQL> create user s ...
- 潭州课堂25班:Ph201805201 django 项目 第二十四课 文章主页 多级评论数据库设计 ,后台代码完成 (课堂笔记)...
加载新闻评论功能 1.分析 业务处理流程: 判断前端传的新闻id是否为空,是否为整数.是否不存在 请求方法:GET url定义:'/news/<int:news_id>' 请求参数:url ...
最新文章
- 面试官:谈一下你对DDD的理解?我:马什么梅?
- 面向对象的三个基本特征 和 五种设计原则
- mysql日志的作用_MySQL 日志相关知识总结
- STM32 进阶教程 2 - micropython 使用
- 语音识别:时间序列的匹配算法(Needleman-Wunsch 算法)
- Flex, SilverLight 和 JavaFX
- 字符串(AC自动机(fail tree))
- angular8实现对象数组根据某个属性排序(多个也可以)
- UWP平台Taglib编译(1)
- linux中的rootfs/initrd/ramfs/initramfs
- 如何列出mongo shell中的所有集合?
- c语言实现字符串转16进制,C语言实现字符串中(10进制和16进制)转成十进制数(示例代码)...
- 跟着小甲鱼学习C语言
- 虚拟机linux删除文件后未释放空间,【Linux命令】删除大文件后磁盘空间未释放问题...
- java给word增加页码_Java 添加页码到Word文档
- link和import的区别,src和href的区别,css hark 以及HTML5及css3的新增特性
- 已经开工三天的软件测试工程师:被女足和谷爱凌感动到了
- instagram架构_Facebook如何收购Instagram内幕故事
- 适用于高级别自动驾驶的驾驶员可预见误用仿真测试
- epel yum 安装 trickle
热门文章
- [EDA]Quartus II 实验简答题
- [蓝桥杯][2013年第四届真题]核桃的数量-枚举(水题)
- 写出TREE-MINIMUM 和TREE-MAXIMUM的递归版本(算法导论第三版12.2-2)
- word List 10
- 深入理解 JVM Class文件格式(七)
- 基础篇--Java IO--概览
- P4175 [CTSC2008]网络管理(整体二分)
- P1829 [国家集训队]Crash的数字表格(推了好久的mobius反演)
- 2020 ICPC 上海 Sum of Log 数位dp + 状态剪枝
- P2607 [ZJOI2008]骑士