分享

韩顺平.玩转oracle笔记总汇二

 cjxzq 2018-05-12

 BEGIN 21-23 ************************** 

ORACLE数据库之约束、索引、权限、角色

1、 维护数据完整性

数据完整性:1实体完整性 2域完整性  3参照完整性

    数据完整性:数据遵从一定的商业和逻辑规则;

    在Oracle数据库里,数据完整性可以使用约束、触发器、应用程序(过程、函数);

    其中约束易于维护,性能优良,所以将约束作为维护数据完整性的首选

    Not null    非空    说明

    Unique      唯一    不重复,可为空

    Primary key 主键    不重复,不可为空

    Foreign key 外键

    Check       检查约束

2、创建与管理索引

    索引 :是用于加快数据存取速度的数据对象,合理的使用索引可以大大降低IO次数,从而提高数据访问性能

    索引使用原则

1、 在大表上建立索引

2、 在where子句或是连接条件上经常引用的列上建立索引

3、 索引的层次不要超过4层(多级索引)

索引的缺点:

    1、建立索引,系统要占用大约为表1.2倍的硬盘和内存空间来保存索引

    2、更新数据的时候,系统必须要有额外的时间来同时对索引进行更新,以维持数据和索引的一致性

    实战表明:不恰当的索引不但于事无补,反而会降低系统性能,因为大量的使用索引,在进行插入、修改和删除操作时比没有索引花费更多的系统时间

在如下情况下建立索引是不恰当的

        1、很少或从不引用的字段

        2、逻辑型的字段,如男或女

    综上所述、提高查询效率是以一定比例的系统资源为代价的,索引不能盲目建立,这是考验一个优秀DBA的重要指标

    1单列索引

        顾名思义就是基于单个列所建立的索引

         : create index i_name on t_name(column_name)

在costomer表的name列建立索引     

Create index nameIndex on customer(name);

    2复合索引

        顾名思义就是基于多列column所建立的索引,在同一张表上可以有不同的索引,但是要求列的组合必须不同

索引重载:create index emp_idx1 on emp(ename,job)

create index emp_idx1 on emp(job,name)

索引管理

        显示表的所有索引 ,当然是通过查 询数据字典视图了,dba_indexes 和 user_indexes,可以显示索引信息,其实dba_indexes用于显示数据库所有的索引信息,而user_indexes对于显示当前用户的索引信息

如: select index_name,index_type,from user_indexes where table_name=’’表名;

 

显示索引列

如 select table_name,column_name from user_ind_columns where index_name=’’索引名称;

3、管理权限和角色

    1、查看系统所有的系统权限

        如:select * from system_privilege_map order by name;

2、查看系统所有的对象权限

    如select * from dba_roles;

3、授予系统权限

    Grant  privilege_name to user [with admin option];

    回收 revoke privilege_name from user

    系统权限不可跨级

4、授予对象权限

    常用的对象权限,有如 alter delete select insert update index references execute,通过select * from dba_tab_privs,对象的拥有者及DBA可授予对象权限

命令如下:

Grant privilege_name on t_name(column1,column2…) to user_name With grant option

回收对象权限

命令如:Revoke privilege_name on table_name(column1,column2) from user_name;

角色:

1、 预定义角色 ;2、自定义角色;

2、 最常用的三个预定义角色1、CONNECT; 2、RESOURCE; 3、DBA;

3、 自定义角色1、无验证;2 、验证;

1、 无验证式 create role role_name not identified

2、 验证式 create role role_name indentified by password_values; 

pl-sql编程 (重中之重

pl/sql 是在标准sql语言上的扩展,可以说是sql语句、常量变量、条件循环语句、异常处理、、、的集合

sql第四代语言结合了第三代语言里像C++,java里的一些常变量、选择循环等

pl\sql将第四代语言的强大功能和灵活性和第三代语言的过程结构融化为一体

 

pl\sql 缺点:1、移植性

Block 结构 1 declare part 2 execution part 3 exception part

Set serveroutput on/off 服务器控制台输出设置 on/off

 

ACID指数据库事务正确执行的四个基本要素的缩写。包含:原子性(Atomicity)一致性(Consistency)隔离性(Isolation)持久性(Durability)。一个支持事务(Transaction)的数据库系统,必需要具有这四种特性,否则在事务过程(Transaction processing)当中无法保证数据的正确性,交易过程极可能达不到交易方的要求。

  原子性

  整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。

  一致性

  在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。

  隔离性

  两个事务的执行是互不干扰的,一个事务不可能看到其他事务运行时,中间某一时刻的数据。

  持久性

  在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。

 

数据类型与类型转换

Number(m,n) : m表示有效数字的位数,n是小数点以后的位数。N 可以是正数,负数,0

若数有效位超过m,则发生错误

正数表示:小数点往右舍入

负数表示:小数点往左舍入

请看下面示例:

原始值

实际值

输出结果

Number

9999.99

9999.99

Number(5)

9999

9999

Number(4)

99999

错误,超出位数

Number(3,2)

999.99

错误,超出位数

Number(4,1)

34.56

34.6

Number(4,2)

34.56

34.56

Number(4,-1)

3333

3330

Number(4,-2)

3333

3300

Number(4,-3)

3333

3000

 

 

 

 

 

PLS_Integer与Binary_Integer及number的比较

PLS_Integer,Binary_Integer只能存储整数类型的数值,而number则兼容

当PLS_Integer发生溢出时,系统报出异常

当Binary_Integer发生溢出时,系统会自动指定一个number类型来代替这个Binary_Integer,此Number拥有最大的值范围

 

简单的类型转换

To_char

To_date

To_number

变量的命名规范:

1、 变量名必须以字母开头

2、 变量名中,特殊字符只能为这三种 # $ _

3、 变量名不能有空格

4、 变量长度不要超过30个字符

变量属性

    %TYPE 是一个伟大的发明

使用格式如下:varName t_name.col_name%TYPE

说明:这样就把t_name表里的col_name字段的属性类型交给了变量varName

 优点: 1、不用再去关心所定义字段的数据类型

        2、当t_name表里的数据类型发生变化时,varName的类型也自动随之变化

 

    %ROWTYPE 我们知道%TYPE是用来将表字段的类型定义给变量的,作用范围是一列,而%ROWTYPE是将表的行数据的记录整体给出,一个是一列,一个是多列;

 

流程控制

1、 IF-THEN-ELSE(条件控制)

IF boolean_expresion1 THEN

   DOsomething1;

ELSIF Boolean_expresion2 THEN

   DOsomething2;

ELSE

   DOsomething3;

END IF;

 

在编写pl/sql程序时,可以定义变量和常量;在pl/sql程序中包括有

1、 标量类型(scalar)

2、 复合类型(composite)

3、 参照类型(reference)

4、 Lob(large object)

2、 CASE语句

BEGIN

CASE    tag

    WHEN result1 THEN

    DOsomething1;

    WHEN result2 THEN

    DOsomething2;

END CASE;

    END;

3、 LOOP循环控制

LOOP

----sequence of statements

END LOOP;

4、 FOR-LOOP循环

FOR Loop_counter IN[REVERSE] low..high LOOP

     Sequence of statements;

END LOOP;

5、 WHILE-LOOP循环

WHILE    condtion LOOP

Sequences of statements;

END LOOP;

6、 GOTO顺序语句

语法 GOTO label_name;

可以在语句块的任何位置定义这样的 label ,定义格式:<<label_name>>

7、 异常处理

BEGIN

     EXCEPTION

WHEN NO_DATA_FOUND      THEN

DOsomething………

    END;

存储过程带输入型的参数时

    如CREATE OR REPLACE PROCEDURE p_name (v1 type,v2 type) IS / AS

其中只需指定v1,v2的类型即可,而不需要为其指定特定大小。这点需要注意

过程调用:call/execute p_name;

 

包是组合存储过程与函数的逻辑集合

包的定义声明:

    Create package p_name is

        Procedure p_name(name varchar2,newsal number);

        Function f_name(name varchar2) return number;

    End;

包体实现

    Create package p_name is

        Procedure p_name(name varchar2,newsal number) is

            Begin

                    ……

            End;

        Function f_name(name varchar2) return number is

        Annual_salary number;

        Begin

            …….

Return annual_salary;

        End;

DECLARE

result varchar2(20);

begin

    result:=sp_f1('peter');

    DBMS_OUTPUT.PUT_LINE('hello '|| result);

end;

 

游标

游标CURSOR是oracle系统内存中开辟的一个查询结果的工作区,其中存放着select语句的查询结果。其结果可以是单条记录、多条记录,也可以是零条记录,游标工作工中存在着一个指针POINTER在初始状态它指向 查询结果的首记录

显示游标的操作

1、 定义游标 2、打开游标  3、检索游标 4、关闭游标

2、 语法格式

3、 CURSOR cursor_name IS select_statement ;

4、 说明

5、 游标必须在PL/SQL块的声明部分进行定义;

6、 游标定义时可以引用PL/SQL变量,但变量必须在游标定义之前定义;

7、 定义游标时并没有生成数据,只是将定义信息保存到数据字典中;

8、 游标定义后,可以使用cursor_name%ROWTYPE定义游标类型变量。

9、 OPEN cursor_name;

declare

--定义游标类型

type sp_emp_cursor is ref cursor;

--定义游标变量

test_cursor sp_emp_cursor;

定义变量 提供接受

v_ename emp.ename%type;

v_sal emp.sal%type;

begin

--将游标变量与一个特定的查询语句相关联起来 open cursor_name for select ......;得到返回结果集

open test_cursor for select ename,sal from emp where deptno=&no;

--通过循环取出test_cursor里的数据

loop

--通过fetch test_cursor into 变量,当然了取的顺序要和查询的顺序相一致

fetch test_cursor into v_ename,v_sal;

--exit when cursor_name%notfound 当游标里不再有数据结果时,则退出循环

exit when test_cursor%notfound;

--打印记录

dbms_output.put_line('名字: '||v_ename || ' 工资: '|| v_sal);

end loop;

end;

/

游标变量与select结合取回其结果集

 

包:

create or replace package mypackage as

type test_cursor is ref cursor;

end mypackage;

/

存储过程:

create or replace procedure sp_java

(spNo in number,p_cursor out mypackage.test_cursor) is

Begin  

open p_cursor for select * from emp where deptno=spNo;

end;

/

 

标注变量在java程序中调用使用,得到结果集合

 

分页查询存储过程

--分页查询封闭于存储过程中

create or replace procedure pagination

(tableName in varchar2,

pageSize in number,--一页显示记录数

pageNow in number,

rows out number,--总记录数

pageCount out number,--总页数

p_cursor out mypackage.test_cursor --返回的记录数

) is

v_sql varchar2(500);

v_begin number:=(pageNow-1)*pageSize+1;

v_end number:=pageNow*pageSize;

begin

v_sql:= 'select * from (select t1.*,rownum rn from (select * from '|| tableName

||') t1 where rownum<='||v_end||') where rn>='||v_begin;

open p_cursor for v_sql;

v_sql:='select count(*) from '||tableName;

execute immediate v_sql into rows;

if mod(rows,pageSize)=0 then

pageCount:=rows/pageSize;

else

pageCount:=rows/pageSize+1;

end if;

end;

/

视图

视图就是一个虚假的不存在的表这个东西实在是太好了。但是也有其缺点、知道是什么呢、因为它是虚拟的。所以它的真实存在是在内存里的。因为性能可并不好。oK.又一次体现了两面性。

 

补充知识: ORACLE 的优化器与执行计划

SQL语句在ORACLE数据库里的执行步骤:

1、 语法检查 检查SQL语句的拼写及词序是否正确

2、 语义分析 核实所有与数据字典里不一致的表和列的名字

3、 概要存在检查 检查数据字典,以确定此SQL语句的概要是否已经存在

4、 生成执行计划使用基于成本的优化规则和数据字典中的统计信息表来决定最佳执行计

5、 建立二进制代码 基于执行计划,Oracle生成二进制执行代码

 

SQL语句的执行计划包括下面三点

1、 语句所引用的表的顺序

2、 语句中所涉及到的表的访问方法

3、 语句中连接操作所影响到的各表的连接方法

 

Oracle OPTIMIZER的管理模式 Mode

1:rule 基于规则 RBO RULE BASED OPTIMIAER

2:CHOOSE Oracle默认情况下的优化方式。指的是当一个表有或索引有统计信息时,则走CBO方式;如果表或索引没有统计信息,表又不是特别小,而且相应的列有索引时,那就走过些,采用RBO的方法

3:first_rows方法 与CHOOSE方式相似,所不同的是,当一个表或索引有统计信息时,它将以最快的方式返回查询的最先几行数据,从总体上减少了响应时间

4:all_rows 这个就是传说中的CBO方法,基本COST方式的,它将以最快的方式返回所有 的行,从总体上提高查询的吞吐量。没有统计信息当然只能走基于规则的方式了

 

执行管理计划的工作原理

在11G之前,我们可以使用存储大纲stored outline和SQL profile来帮助我们固定特定的SQL语句的执行计划,防止由于执行计划更改而导致的性能下降。不过这样的工作似乎烦重了。因为这两项目工作都是需要DBA手动完成的;

11G开始 引入了执行计划管理器的概念 SQL PLAN MANAGEMENT这个新特性

为实现执行计划管理,优化器会为所有执行次数超过一次的SQL语句维护此SQL语句的每个执行计划的历史列表PLAN HISTROY。优化器通过维护一个语句执行的日志条目来识别此SQL语句是否为第二次执行。一旦优化器认出此SQL语句为第二次执行;

Plan baseline是plan histroy里的一个子集,plan baseline里的执行计划是用来性能比较好坏的一个依据。

 

 

ORACLE参数文件管理

参数文件包含了所有的数据库配置信息,它非常重要;参数文件里的信息有点像map对象,都是通过key_value来进行保存的.

 

 

 

 


在oracle 9i之前,参数文件只有一种那就是基于文本的pfile文件

说是文本文件当然了可以通过文本等编辑器直接修改。

而在9i之后,数据库参数文件的性提高了。采用了基于服务器的参

数文件即spfile(server parameter file),它是一种二进制文件,

它只能通过数据库连接之后,再获得相应的权限之后,才能对此文

件做出修改。当然了一些的软件产品都必须要考虑到向后兼容这一特点。当然了保留了pfile的功能,在有需要的时候,可以通过create spfile=’’ from pfile=’’反之亦然创建相应需要的文件类型。

Show parameter或select * from V$parameter数据字典表查询得知

或show parameter XXX进行like式的模糊查询。

只有在知道了参数文件的前提下才知道了控制文件,因为参数文件里的一个参数control_files记录了控制文件存入的绝对路径即位置.

OK 控制文件到底记录了什么呢

记录了数据及日志文件的位置

日志序列号 检查点 日志历史

数据库名

Alter system set control_files=’’ scope=spfile;

Oracle文件必须包含

参数文件

    数据库基本参数/SGA区占用内存的大小/进程的行为,控制文件的位置

2控制文件

    基本控制信息/系统的SCN码/数据库运行模式/数据文件和日志文件的位置

3数据文件

    也叫表空间文件,存储数据

重作日志文件

    记录数据修改信息

Startup restrict这时数据库只有restricted session权限的用户才可以连接上数据库

这样有有利于数据库的管理和维护

 

数据库关闭方式

1/shutdown normal 等所有用户都退出系统之后才能开始关闭数据库

2/shutdown transactional 新的用户不能连接数据库,没有事务的直到直接衩断开连接.有事务的用户数据库等到此用户执行了COMMIT之后断开连接(一句话解释-就是没有事务的直接断开连接)

,当所有用户都断开连接,数据库开始关闭

3/shutdown immediate 新的用户不能连接数据库,没有事务的用户直接衩断开连接.对于 有事务的用户强行执行rollback操作后断开连接(比shutdown transactional更狠一点,就是有事务的也不等了,直接rollback to savepoint了)

4/shutdown abort直接杀死Oracle进程()这个其实是很有风险的一件事,除非到了不得不用的地步。否则不要用shutdown abort强制关闭数据库连接

 

数据库设计准则(第一、第二、第三范式说明)

I、关系数据库设计范式介绍1.1 第一范式(1NF无重复的列

 

      所谓第一范式(1NF)是指数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。如果出现重复的属性,就可能需要定义一个新的实体,新的实体由重复的属性构成,新实体与原实体之间为一对多关系。在第一范式(1NF)中表的每一行只包含一个实例的信息。简而言之,第一范式就是无重复的列。

 

说明:在任何一个关系数据库中,第一范式(1NF)是对关系模式的基本要求,不满足第一范式(1NF)的数据库就不是关系数据库。

 

 

1.2 第二范式(2NF)属性完全依赖于主键[消除部分子函数依赖]

 

      第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。第二范式(2NF)要求数据库表中的每个实例或行必须可以被惟一地区分。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。例如员工信息表中加上了员工编号(emp_id)列,因为每个员工的员工编号是惟一的,因此每个员工可以被惟一区分。这个惟一属性列被称为主关键字或主键、主码。

        第二范式(2NF)要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性,如果存在,那么这个属性和主关键字的这一部分应该分离出来形成一个新的实体,新实体与原实体之间是一对多的关系。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。简而言之,第二范式就是属性完全依赖于主键。

 

 

1.3 第三范式(3NF)属性不依赖于其它非主属性[消除传递依赖]

 

            满足第三范式(3NF)必须先满足第二范式(2NF)。简而言之,第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。例如,存在一个部门信息表,其中每个部门有部门编号(dept_id)、部门名称、部门简介等信息。那么在的员工信息表中列出部门编号后就不能再将部门名称、部门简介等与部门有关的信息再加入员工信息表中。如果不存在部门信息表,则根据第三范式(3NF)也应该构建它,否则就会有大量的数据冗余。简而言之,第三范式就是属性不依赖于其它非主属性。

 

 

 

II、范式应用实例剖析

        下面以一个学校的学生系统为例分析说明,这几个范式的应用。首先第一范式(1NF):数据库表中的字段都是单一属性的,不可再分。这个单一属性由基本类型构成,包括整型、实数、字符型、逻辑型、日期型等。在当前的任何关系数据库管理系统(DBMS)中,傻瓜也不可能做出不符合第一范式的数据库,因为这些DBMS不允许你把数据库表的一列再分成二列或多列。因此,你想在现有的DBMS中设计出不符合第一范式的数据库都是不可能的。

首先我们确定一下要设计的内容包括那些。学号、学生姓名、年龄、性别、课程、课程学分、系别、学科成绩,系办地址、系办电话等信息。为了简单我们暂时只考虑这些字段信息。我们对于这些信息,说关心的问题有如下几个方面。

 

学生有那些基本信息

学生选了那些课,成绩是什么

每个课的学分是多少

学生属于那个系,系的基本信息是什么。

 

 

2.1 第二范式(2NF)实例分析

 

      首先我们考虑,把所有这些信息放到一个表中(学号,学生姓名、年龄、性别、课程、课程学分、系别、学科成绩,系办地址、系办电话)下面存在如下的依赖关系。

        (学号)→ (姓名年龄,性别,系别,系办地址、系办电话)

         (课程名称) → (学分)

        (学号,课程)→ (学科成绩)

2.1.1 问题分析

 

      因此不满足第二范式的要求,会产生如下问题

 

 

        数据冗余: 同一门课程由n个学生选修,"学分"就重复n-1次;同一个学生选修了m门课程,姓名和年龄就重复了m-1次。

 

        更新异常:

             1)若调整了某门课程的学分,数据表中所有行的"学分"值都要更新,否则会出现同一门课程学分不同的情况。

            2)假设要开设一门新的课程,暂时还没有人选修。这样,由于还没有"学号"关键字,课程名称和学分也无法记录入数据库。

 

       删除异常  假设一批学生已经完成课程的选修,这些选修记录就应该从数据库表中删除。但是,与此同时,课程名称和学分信息也被删除了。很显然,这也会导致插入异常。

2.1.2 解决方案

 

      把选课关系表SelectCourse改为如下三个表:

学生:Student(学号,姓名年龄,性别,系别,系办地址、系办电话)

课程:Course(课程名称学分)

选课关系:SelectCourse(学号课程名称成绩)

2.2 第三范式(3NF)实例分析

 

        接着看上面的学生表Student(学号,姓名年龄,性别,系别,系办地址、系办电话),关键字为单一关键字"学号",因为存在如下决定关系:

 

       (学号)→ (姓名年龄,性别,系别,系办地址、系办电话)

        但是还存在下面的决定关系

       (学号) → (所在学院)→(学院地点学院电话)

        即存在非关键字段"学院地点""学院电话"对关键字段"学号"的传递函数依赖。

        它也会存在数据冗余、更新异常、插入异常和删除异常的情况。 (数据的更新,删除异常这里就不分析了,可以参照2.1.1进行分析)

 

        根据第三范式把学生关系表分为如下两个表就可以满足第三范式了:

 

        学生:(学号姓名年龄性别,系别)

        系别:(系别系办地址、系办电话)

 

触发器的概念

触发器是命名块的一种。

触发器的执行是自动进行的,当相应事件发生时就会激发触发器的执行。

触发器不接受任何参数

触发器(TRIGGER)作用

维护那些通过创建表时的声明约束不可能实现的复杂的完整性约束

通过记录已进行的改变及是谁进行了该项改变来检查一个表中的信息。

当一个表发生改变时,自动向其他程序发送需要采取行动的信号

在一个发布-预定环境中发布关于各种事件的信息。

触发器类型

DML触发器

INSERTDELETEUPDATE

INSTEAD-OF  触发器

只可以定义为视图的触发器

系统触发器

数据库启动或关闭之类的系统事件发生时触发

在执行诸如创建表之类的DDL操作时触发

触发器组成

触发器由触发器头部和触发器体两个部分组成,主要包括以下参数:

作用对象:表、视图、数据库、模式

触发事件:DMLDDL、数据库系统事件

触发时间:BEFOREAFTER

触发级别:语句级、行级

触发条件:WHEN条件

触发操作:SQL语句、PL/SQL

DML触发器的种类以及执行顺序

语句级前触发器

行级前触发器

DML操作(触发事件)

行级后触发器

语句级后触发器

CREATE [OR REPLACE] TRIGGER trigger_name

BEFORE|AFTER triggering_event [OF column_name]

ON table_name

[FOR EACH ROW]

[WHEN trigger_condition]

DECLARE

     

BEGIN

     

EXCEPTION

     

END [trigger_name];

创建一个触发器,禁止在休息日改变雇员信息,

create or replace trigger tr_sec_emp

before insert or update or delete on emp

begin

  if to_char(sysdate,'DY') in ('星期六','星期日') then

    raise_application_error(-20001,'不能在休息日修改员工信息');

  end if;

end;

判断当前执行的触发器到底是有那个DML操作激发的。

谓词

行为

INSERTING

如果触发语句是INSERT,则为TRUE;否则为FALSE

UPDATING

如果触发语句是UPDATE,则为TRUE;否则为FALSE

DELETING

如果触发语句是DELETE,则为TRUE;否则为FALSE

emp表创建一个触发器,当执行插入操作时,统计操作后员工人数;当执行更新工资操作时,统计更新后员工平均工资;当执行删除操作时,统计删除后各个部门的人数。

CREATE OR REPLACE TRIGGER trg_emp_dml

AFTER INSERT OR UPDATE OR DELETE ON emp

DECLARE

  v_count NUMBER;

v_sal   NUMBER(6,2);

BEGIN

  IF INSERTING THEN

    SELECT count(*) INTO v_count FROM emp;

    DBMS_OUTPUT.PUT_LINE(v_count);

  ELSIF UPDATING THEN

    SELECT avg(sal) INTO v_sal FROM emp;

    DBMS_OUTPUT.PUT_LINE(v_sal);

  ELSE

    FOR v_dept IN (SELECT deptno,count(*) num FROM emp GROUP BY deptno) LOOP

      DBMS_OUTPUT.PUT_LINE(v_dept.deptno||' '||v_dept.num);

    END LOOP;

  END IF;

END trg_emp_dml;

 

行级触发器

是指执行DML操作时,每操作一记录,触发器就执行一次,一个DML操作涉及到多少个记录,触发器就执行多少次。

在行级触发器中可以使用WHEN条件,进一步控制触发器的执行。

在触发器体中,可以对当前操作的记录进行访问和操作。

标识符

触发语句

old

new

INSERT

未定义,所有字段都为NULL

当语句完成时,将要被插入的值

UPDATE

更新前行的原始值

当语句完成时,将要被更新的值

DELETE

行被删除前的原始值

未定义,所有字段都为NULL

   

old.field:new.field (执行部分)

old.field new.field   (WHEN条件中)

在不同操作中的意义

emp表创建一个触发器,当插入新员工时显示新员工的员工号、员工名;当更新员工工资时,显示修改前后员工工资;当删除员工时,显示被删除的员工号、员工名。

CREATE OR REPLACE TRIGGER trg_emp_dml_row

BEFORE INSERT OR UPDATE OR DELETE ON emp

FOR EACH ROW

BEGIN

   IF INSERTING THEN

         DBMS_OUTPUT.PUT_LINE(:new.empno||' '||

                                                :new.ename);

   ELSIF UPDATING THEN

         DBMS_OUTPUT.PUT_LINE(:old.sal||' '||:new.sal);

   ELSE

         DBMS_OUTPUT.PUT_LINE(:old.empno||' '||

                                                :old.ename);

   END IF;

END trg_emp_dml_row;

在行级触发器中,可以使用WHEN子句进一步控制触发器的执行。

修改员工工资时,保证修改后的工资高于修改前的工资。

CREATE OR REPLACE TRIGGER trg_emp_update_row

BEFORE UPDATE OF sal ON emp

FOR EACH ROW

WHEN(new.sal<=old.sal)

BEGIN

    RAISE_APPLICATION_ERROR(

                    -20001,'The salary is lower!');

END trg_emp_update_row;

 

特点

只能定义在视图上

Instead-of触发器是行级触发器

Instead-of 触发器由DML操作激发,而DML操作本身并不执行

作用

修改一个本来不可以修改的视图

修改视图中某嵌套表列的列

如果视图中包含下列任何一项,则该视图不可修改

集合操作符

聚集函数

GROUP BYCONNECT BY START WITH子句

DISTINCT

连接(部分包含连接的视图)

系统触发器事件

DDL事件

CREATEALTERDROP

数据库事件触发

服务器启动/关闭、用户登陆/注销以及服务器错误

事件

允许计时

描述

STARTUP

AFTER

当实例开始时激发

SHUTDOWN

BEFORE

当实例关闭时激发

SERVERERROR

AFTER

只要错误发生就激发

LOGON

AFTER

在一个用户成功连接数据库时触发

LOGOFF

BEFORE

在用户注销时开始激发

CREATE

BEFORE,AFTER

创建一个模式对象之前或之后激发

DROP

BEFORE,AFTER

在删除一个模式对象之前或之后激发

ALTER

BEFROE,AFTER

在更改一个模式对象之前或之后激发

将每个用户的登录信息写入到temp_table表中。

 CREATE OR REPLACE TRIGGER log_user_connection

  AFTER LOGON

  ON DATABASE

  BEGIN

       INSERT INTO scott.temp_table

       VALUES (user,sysdate);

  END log_user_connection;

触发器管理

修改触发器

CREATE OR REPLACE TRIGGER trigger_name

重新编译触发器

ALTER TRIGGER trigger_name  COMPILE;

禁用、启用触发器

ALTER TRIGGER trigger_name DISALBLE|ENABLE

禁用、启用某个表相关的所有触发器:

ALTER TABLE table_name

   DISABLE|ENABLE ALL TRIGGERS

删除触发器

DROP TRIGGER  trigger_name;

 

 

读者可能会问,为什么要使用集合呢?毕竟,使用带有外键的两个表已经允许创建数据之间的关联。答案是相对于使用两个表,存储在集合里的数据可以被数据库更快地访问。

1、  index-by (pl/sql2.0及早期版本)

2、  嵌套表(pl/sql8.0或更新)

3、  可变数据VARRAYVARYING ARRAY (pl/sql8.0或更新)

 

大家可能都知道Oracle数据库的核心代码是用C编写的,而一些辅助的工具是通过JAVA语言写的。

 

index by 表类似表C语言中的数组,声明方法如下

TYPE table_type IS TABLE OF TYPE INDEX BY BINARY_INTEGER;

Index by 表中的元素不是按特定顺序排序的,这是与C语言数组不同的,在C语言中数组在内存中是顺序存储的,因此元素下标也是有序的。(有点像hashtable的意思)

index by 表中调用不存在的元素时会提示出错。

嵌套表的声明与index by声明十分相似,具体声明如下:

TYPE table_type IS TABLE OF TYPE;

嵌套表是结构有序的,嵌套表是只读的, NULL初值;

可变数据VARYING ARRAY

TYPE table_name IS VARRAY|VARYING ARRAY(maximun size) OF TYPE NOT NULL

可变数组与C数组相同,结构有序有,大小固定。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多