Oracle例外表学习笔记

DML ErrorLogging

 

Oracle提供了2类的例外表。

 

这是10gR2以后版本才有的新特征

 

DML error logging 是ORACLE10gR2版本中的新特征。这个新的特征是解决如下的问题:假定你要向一个目标表更新或者插入大批数据,过程已经运行了很长时间,就在程序快要结束前,一条违反约束的情况发生了,这个事务也会失败。前面花费很长时间运行的工作作废了不算,还要花费很长时间做ROLLBACK处理,这种情况让人恼怒不已。有DML error logging这个特性,可以避免上述情况,当遇到违反约束的情况下,ORACLE会将该条违反约束的数据记录在另外一张表中,程序继续运行。在整个程序运行完后,可以手动或者编写一段代码,对违反约束的数据进行单独处理。

   

    本节介绍如何INSERT, UPDATE, MERGE 和DELETE如何使用DML ERROR LOGGING。

 

建立一张表

create table dmlel

(

pkey varchar2(100) primary key,

field1  integer,

field2 varchar2(10) not null

);

 

alter table dmlel add constraint check_fiels1_ic

CHECK(regexp_like(field1,'^[0-9]{8,10}$'));

 

这张表存在3个约束。

 

现在编写一个脚本,在这个脚本中没有采用DML error logging

 

假定有一张元数据表,我们要将该表的数据插入

 

drop table dmlel_origin purge;

 

create table dmlel_origin

(

 pkey varchar2(10),

 field1  integer,

 field2 varchar2(10)

);

 

 

begin

for i in 1..10000 loop

insert intodmlel_origin(pkey,field1,field2)

values('I'||to_char(i, '0000000'),trunc(dbms_random.value(10000000,999999999)),'x');

end loop;

commit;

end;

 

select * from dmlel_origin

 

我们增加几条违背约束的数据

 

insert intodmlel_origin(pkey,field1,field2)

values('I 0000005',888888888,'x');

 

insert intodmlel_origin(pkey,field1,field2)

values('I 077777',888888,'x');

 

insert intodmlel_origin(pkey,field1,field2)

values('I 077787',88888888,null);

 

insert intodmlel_origin(pkey,field1,field2)

values('I 0000004',88,null);

 

自动建立日志例外表

declare

begin

  -- Test statements here

  DBMS_ERRLOG.create_error_log('DMLEL','DMLEL_LOG','SCOTT');

end;

 

 

 desc DMLEL_LOG;

Name            Type           Nullable Default Comments

--------------- -------------- -------- ------- --------

ORA_ERR_NUMBER$ NUMBER         Y                        

ORA_ERR_MESG$   VARCHAR2(2000) Y                        

ORA_ERR_ROWID$  UROWID(4000)   Y                        

ORA_ERR_OPTYP$  VARCHAR2(2)    Y                        

ORA_ERR_TAG$    VARCHAR2(2000) Y                        

PKEY            VARCHAR2(4000) Y                        

FIELD1          VARCHAR2(4000) Y                        

FIELD2          VARCHAR2(4000) Y  

insert /*+append*/ into DMLEL

select * from dmlel_origin

 

ORA-02290: 违反检查约束条件 (SCOTT.CHECK_FIELS1_IC)

 

 

truncate table DMLEL

truncate table dmlel_log

 

insert  into DMLEL

select * from dmlel_origin

log errors into dmlel_log('batch_insert'||to_char(sysdate,'yyyymmddhh24:mi:ss')) reject limit unlimited;

 

 

ORA_ERR_NUMBER$

ORA_ERR_MESG$

ORA_ERR_ROWID$

ORA_ERR_OPTYP$

ORA_ERR_TAG$

PKEY

FIELD1

FIELD2

1

ORA-00001: 违反唯一约束条件 (SCOTT.SYS_C0015362)

I

batch_insert20080922 14:59:50

I 0000005

888888888

x

2290

ORA-02290: 违反检查约束条件 (SCOTT.CHECK_FIELS1_IC)

I

batch_insert20080922 14:59:50

I 077777

888888

x

1400

ORA-01400: 无法将 NULL 插入 ("SCOTT"."DMLEL"."FIELD2")

I

batch_insert20080922 14:59:50

I 077787

88888888

1400

ORA-01400: 无法将 NULL 插入 ("SCOTT"."DMLEL"."FIELD2")

I

batch_insert20080922 14:59:50

I 0000004

88

 

注意:1、实际上又一条数据有2个字段违反了约束,但日志例外表只反映出一条

     2、如果rollback的话,例外表数据并没有rollback。可以肯定这是一个自主事务。

     3、ora_err_rowid$为null,这是因为这是一个insert操作。

 

 

你也可以自己手工创建日志例外表,手工创建可以更加个性化地处理违反约束的规则,如果有一张表,有很多的字段,有一些字段上虽然存在约束,但不是关键性的约束,如果采用自动建立日志例外表的方法,这样这张表就可能有很多的字段,这张表占用了更多地空间,这种情况下,就可以自定义日志例外表。

 

drop table DMLEL_LOG_1 purge

 CREATE TABLE DMLEL_LOG_1

   (

  --ORA_ERR_NUMBER$ NUMBER,

    ORA_ERR_MESG$VARCHAR2(2000),

    ORA_ERR_ROWID$ UROWID (4000),

    ORA_ERR_OPTYP$ VARCHAR2(2),

    ORA_ERR_TAG$ VARCHAR2(2000),

    PKEY VARCHAR2(4000),

    FIELD1 VARCHAR2(4000)--,

    --FIELD2 VARCHAR2(4000)

   )

  

truncate table DMLEL;

truncate table dmlel_log;

 

insert  into DMLEL

select * from dmlel_origin

log errors into dmlel_log_1('batch_insert'||to_char(sysdate,'yyyymmddhh24:mi:ss')) reject limit unlimited

 

ORA-38900: 缺失必需的列 "ORA_ERR_NUMBER$" (错误日志表"DMLEL_LOG_1")

 

  drop table DMLEL_LOG_1 purge

  CREATE TABLE DMLEL_LOG_1

   (

 ORA_ERR_NUMBER$ NUMBER,

    ORA_ERR_MESG$VARCHAR2(2000),

    ORA_ERR_ROWID$ UROWID (4000),

    ORA_ERR_OPTYP$ VARCHAR2(2),

    ORA_ERR_TAG$ VARCHAR2(2000),

    PKEY VARCHAR2(4000),

    FIELD1 VARCHAR2(4000)--,

    --FIELD2 VARCHAR2(4000)

   )

  

  

 

truncate table DMLEL;

truncate table dmlel_log_1;

 

insert  into DMLEL

select * from dmlel_origin

log errors into dmlel_log_1('batch_insert'||to_char(sysdate,'yyyymmddhh24:mi:ss')) reject limit unlimited

 

select * from DMLEL_LOG_1

ORA_ERR_NUMBER$

ORA_ERR_MESG$

ORA_ERR_ROWID$

ORA_ERR_OPTYP$

ORA_ERR_TAG$

PKEY

FIELD1

1

ORA-00001: 违反唯一约束条件 (SCOTT.SYS_C0015362)

I

batch_insert20080922 14:59:50

I 0000005

888888888

2290

ORA-02290: 违反检查约束条件 (SCOTT.CHECK_FIELS1_IC)

I

batch_insert20080922 14:59:50

I 077777

888888

1400

ORA-01400: 无法将 NULL 插入 ("SCOTT"."DMLEL"."FIELD2")

I

batch_insert20080922 14:59:50

I 077787

88888888

1400

ORA-01400: 无法将 NULL 插入 ("SCOTT"."DMLEL"."FIELD2")

I

batch_insert20080922 14:59:50

I 0000004

88

 

 

Update DMLEL set field1=123

Where pkey= 'I 0000007'

log errors into dmlel_log_1('update'||to_char(sysdate,'yyyymmddhh24:mi:ss')) reject limit unlimited;

 

selectt.ora_err_mesg$,t.ora_err_rowid$,t.ora_err_optyp$,t.ora_err_tag$ from dmlel_log_1 t

 

 

ORA_ERR_MESG$

ORA_ERR_ROWID$

ORA_

ERR_

OPTYP$

ORA_ERR_TAG$

ORA-00001: 违反唯一约束条件

 (SCOTT.SYS_C0015362)

I

batch_insert20080922 15:15:23

ORA-02290: 违反检查约束条件 (SCOTT.CHECK_FIELS1_IC)

I

batch_insert20080922 15:15:23

ORA-01400: 无法将 NULL 插入 ("SCOTT"."DMLEL"."FIELD2")

I

batch_insert20080922 15:15:23

ORA-01400: 无法将 NULL 插入 ("SCOTT"."DMLEL"."FIELD2")

I

batch_insert20080922 15:15:23

ORA-02290: 违反检查约束条件 (SCOTT.CHECK_FIELS1_IC)

AAAT+gAAEAABh+EAAG

U

update20080922 15:22:47

 

 

 

为了用DML ErrorLogging处理上述错误,首先建立一个错误日志表。

 

建立ErrorLogging Table

 

有2种方法建立Error Logging表,一个方法是手工创建,另一种方法自动创建。以下是自动创建的语法:

begin

    dbms_errlog.create_error_log('DMLEL','ERROR_LOG_DMLEL');

 end;

 

这张表有以下结构:

desc error_log_dmlel

 Name                                     Null?    Type

 ------------------------------------------------- ----------------------------

 ORA_ERR_NUMBER$                                    NUMBER

 ORA_ERR_MESG$                                     VARCHAR2(2000)

 ORA_ERR_ROWID$                                     ROWID

 ORA_ERR_OPTYP$                                    VARCHAR2(2)

 ORA_ERR_TAG$                                       VARCHAR2(2000)

 PKEY                                              VARCHAR2(4000)

 FIELD1                                            VARCHAR2(4000)

 FIELD2                                            VARCHAR2(4000)

 

 

 

ORA_ERR_TAG$列标识出当前处理的信息。

 

DML日志例外表能够处理的错误信息,除了约束外,还可以标识触发器的错误信息,还有类型转化时候发生的错误。

 

CREATE OR REPLACE TRIGGER update_field2

BEFORE UPDATE OF field2 ON dmlel FOR EACH ROW

DECLARE

BEGIN

  if :old.field2 <= :new.field2 then

    raise_application_error(-20105, '新值必须小于旧值');

  end if;

END;

 

Update DMLEL set field2='y'

Where pkey= 'I 0000002'

 

ORA-20105: 新值必须小于旧值

ORA-06512: 在"SCOTT.UPDATE_FIELD2", line 4

ORA-04088: 触发器'SCOTT.UPDATE_FIELD2' 执行过程中出错

 

truncate table dmlel_log_1;

 

Update DMLEL set field2='y'

Where pkey= 'I 0000002'

log errors into dmlel_log_1('update'||to_char(sysdate,'yyyymmddhh24:mi:ss')) reject limit unlimited;

 

ORA_ERR_NUMBER$

20105

ORA_ERR_MESG$

ORA-20105: 新值必须小于旧值
ORA-06512: 在 "SCOTT.UPDATE_FIELD2", line 4
ORA-04088: 触发器 'SCOTT.UPDATE_FIELD2' 执行过程中出错

ORA_ERR_ROWID$

AAAT+gAAEAABh+EAAB

ORA_ERR_OPTYP$

U

ORA_ERR_TAG$

update20080922 17:59:51

PKEY

I 0000002

FIELD1

63370697

第二种形式的例外表,其格式为

 

create table excep_check_field1(

row_id rowid,

owner varchar2(30),

table_name varchar2(30),

constraint varchar2(30)

);

excep_check_field1为例外表的名称

 

我们在dmlel_origin故意插入2条违反约束

regexp_like(field1,'^[0-9]{8,10}$')

的2条数据;

 

insert intodmlel_origin(pkey,field1,field2)

values('I 077777',888888,'x');

 

insert intodmlel_origin(pkey,field1,field2)

values('I 0000004',88,null);

 

我们运行以下脚本,找出这2条数据:

truncate table excep_check_field1;

 

alter table dmlel_origin add constraintcheck_fiels1_ic

CHECK( regexp_like(field1,'^[0-9]{8,10}$'))

enable validate exceptions into exceptions

 

ORA-02264: 名称已被一现有约束条件占用

上面过程虽然没有成功,但是在例外表中记录了违反constraintcheck_fiels1_ic的2条数据;

 

select * from excep_check_field1

ROW_ID

OWNER

TABLE_NAME

CONSTRAINT

AAAT+YAAEAABh99AEk

SCOTT

DMLEL_ORIGIN

CHECK_FIELS1_IC_1

AAAT+YAAEAABh99AEm

SCOTT

DMLEL_ORIGIN

CHECK_FIELS1_IC_1

 

Select field1 from dmlel_origin where rowid in(select row_id from excep_check_field1)

 

删除修改违反约束的数据,再添加约束

Delete from dmlel_origin

where rowid in(select row_id from excep_check_field1)

 

truncate table excep_check_field1;

 

alter table dmlel_origin add constraint check_fiels1_ic_1

CHECK(regexp_like(field1,'^[0-9]{8,10}$'))

enable validate exceptions into excep_check_field1;

 

Table altered

这一次,表被成功修改。

 

 原创文章,如果转载,请标注作者:田文  CSDN地址:http://blog.csdn.net/tiwen818

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
从一个“普通”的Oracle DBA(Oracle数据库管理员)转变为Oracle Applications DBA(Oracle应用程序数据库管理员),有两个内容你必须去弄清楚。第一个内容是如何成为一个Oracle Applications DBA(Oracle应用程序数据库管理员)。第二个内容是你要搞清楚Oracle应用程序背后的架构体系,也就是说你要明白诸如以下产品的结构体系:Oracle电子商务套件、Oracle 11i数据库、Siebel产品等。 本文首先讲述如何从一个普通的Oracle DBA转变为一个Oracle Applications DBA(Oracle应用程序数据库管理员),接着讲述一些Oracle应用软件架构方面的内容 。 如何成为Oracle应用程序数据库管理员 首先是角色的转变 Oracle Applications DBA(Oracle应用程序数据库管理员)对“普通”的Oracle DBA(Oracle数据库管理员)来说是一个很大的挑战。拿Oracle EBS DBA(Oracle 电子商务套件DBA)来说,不仅需要了解EBS的各个组件、服务,而且还要更主动和其他相关人员接触。 一个Oracle Applications DBA(Oracle应用程序数据库管理员)不仅需要和其他DBA一样去负责managing、 sizing、maintaining和 tuning database这些日常的数据库管理的工作,如果他的Apps database是OLTP系统的话,他还需要监察wait和lock 。Oracle E-Business Suite还有一些特性需要DBA去完成,比如从外部资源里灌数据到Apps database里,或支持开发人员从已有数据中提取数据。 接着工作内容的转变 作为一个Oracle Applications DBA(Oracle应用程序数据库管理员),要想更好的对Oracle Application database做支持,需要仔细记住以下几项。 1.网络上没有什么比较容易简单的文档让你去熟悉Apps DBA,所以我建议去看帮助。 2.在你没有经过多次测试并且得到客户认可的时候不要去打补丁,并且你要确信这个补丁解决了现有的问题,而且没有带来其它新的问题。 3.记住Oracle Applications会有很多索引,定期rebuild index会对性能有好处,当然做这项工作应该在系统的空闲时间。 4.不要为了提高性能而在没有询问oracle Support前试着去增加额外的indexes。如果你一定要去做,那千万记住要有文档作记录,因为在这之后你再打patch的时候它可能会把你做的修改自动复原。 5. 知道怎么样是正确的打patch,先计划打哪个patch,然后取得patch,接着打patch,测试,最后文档记录。 6. 要知道任何时刻数据库都可能会有一些object 是invalid的,你的一些操作也会增加invalid objects,定期检查这些invalid objects的数量,然后定期用utlrp去重新编译,utlrp.squ在ORACLE HOME的rdbms/admin下,需要用SYS运行。在你的DB运行过程中如果碰到错误,就可以先重新编译invalid objects,如果没有解决问题再去递交iTAR(Internet created Technical Assistance Request). 7.能看懂日志。 8.了解Apps database的环境,包括操作系统和DB的,当你对你的工作环境了如指掌后,一切也就变得容易了,那时,你就是一个悠闲的Apps DBA了。 另外,对于APPS DB(应用程序数据库)来说,你可能需要创建或拷贝(克隆)多个生产库以外的数据库,比如测试和开发数据库,当然,需要多少数据库是由你的商业需求所决定的。开发环境数据库是供开发人员进行report,PL/SQL等开发的,这个环境可以在开发人员觉得数据已经不再满足开发需求的时候,当然也可以在这个环境测试补丁(patches)。当然最终使用patch的时候还需要在测试环境做测试,因为测试数据库是和生产数据库环境最接近的。(上面说的克隆cloning是一种将applications layer和database layer完全复制的一种方法。)所以,当你拥有这三个数据库的时候,打patch的步骤是先development database再test database最后才在production database环境应用。 构架应用体系 如果你研究过Oracle Forms,使用过Application Server和Devel

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值