获取导致导入失败的数据(三)
上一篇 / 下一篇 2008-05-10 23:54:33 / 个人分类:ORACLE
前不久从一个数据库执行导出操作时报错,通过直接路径方式跳过后,导入时候再次报错。推测是由于源数据库出现的异常导致表中数据超过表定义的精度。
由于源数据库中错误记录已经被删除,因此只能想办法从导出的dmp文件中获取错误的记录。
导出、导入过程的描述可以参考:
EXP在9R2上导出时报错ORA-3113和ORA-24324:http://yangtingkun.itpub.net/post/468/460647
EXP在9R2上导出时报错ORA-3113和ORA-24324(二):http://yangtingkun.itpub.net/post/468/460831
继续寻找解决问题的方法,并最终获取了导致错误的记录。
获取导致导入失败的数据:http://yangtingkun.itpub.net/post/468/461401
获取导致导入失败的数据(二):http://yangtingkun.itpub.net/post/468/461600
BEFORE触发器修正数据错误:http://yangtingkun.itpub.net/post/468/461506
在上一篇中,发现采用系统触发器的方法只能获取导入操作的语句,也就是说,获取的SQL是所有问题的起源SQL,而并非导致操作的SQL语句。
也就是说,利用触发器获取错误信息的方式是行不通的。既然触发器中引发错误的SQL无法被系统触发器所捕获,那么这个SQL能不能被Oracle的V$SQL所捕获呢。
先做个测试,看看这种由于精度问题导致的SQL语句是否可以从V$SQL中查询到:
SQL> CREATE TABLE TEST (ID NUMBER(3));
表已创建。
SQL> INSERT INTO TEST VALUES (100);
已创建1行。
SQL> INSERT INTO TEST VALUES (1000);
3T4S@"p7wx0INSERT INTO TEST VALUES (1000)
6_MR%DM.?(E0 *
T5u5B.|ipx0ERROR位于第1行:ITPUB个人空间_3|3Z*e+z@.C.g
ORA-01438:值大于此列指定的允许精确度
ITPUB个人空间(t#}k$wa;T6k
SQL> SELECT SQL_TEXT FROM V$SQL WHERE SQL_TEXT LIKE 'INSERT INTO TEST VALUES%';
SQL_TEXT
5m}5F(HuW1aYrZ0-----------------------------------------------------------------------------ITPUB个人空间%Vy-r)h$a6N"a-Rv
INSERT INTO TEST VALUES (1000)
A6B:ka G qb1Pa0INSERT INTO TEST VALUES (100)
从上面的结果可以看到,由于精度问题出现的错误,是会被Oracle的V$SQL所记录下来的,但是如果分析阶段报错,就无法从V$SQL中查询了:
SQL> SELECT * FROM ASDFA;
~;} ZE3VY4r HB(|0SELECT * FROM ASDFA
6N0f-`+K`:~/c0s0 *ITPUB个人空间 r!N1j6b7{d_
ERROR位于第1行:
_ d:|]-oOz,^^0ORA-00942:表或视图不存在
SQL> SELECT SQL_TEXT FROM V$SQL WHERE SQL_TEXT LIKE '%ASDFA%';ITPUB个人空间J
F4H*b'H(M:}Z)`5^
SQL_TEXTITPUB个人空间.feL?p8e3f_
---------------------------------------------------------
n2A1F(Qr(r0SELECT SQL_TEXT FROM V$SQL WHERE SQL_TEXT LIKE '%ASDFA%'
而根据上面最后一次的导入报错信息看,似乎获取的数值格式错误,出现了逗号,导致触发器中SQL语句分析时报错,而这种方式是无法被V$SQL所捕获的。
下面修改SHGOV_ORDER_BAK表,将字段改为VARCHAR2(4000),并修改触发器,使之按照字符类型插入数据:
SQL> DROP TABLE SHGOV_ORDER_BAK;
表已丢弃。
SQL> CREATE TABLE SHGOV_ORDER_BAK
j?B%n
e0 2 (
-R| U^D;in6o v0 3 TRADE_RATE VARCHAR2(4000),
gL.S$l,AG0 4 ORDER_AMOUONT VARCHAR2(4000),
N&@b)AO4x7s0 5 SEND_AMOUNT VARCHAR2(4000),ITPUB个人空间0^z%l%} ~ Ec*b
6 RECEIVE_AMOUNT VARCHAR2(4000),
#Ktm#^? QR}0 7 UNIT_PRICE VARCHAR2(4000),
d^{ fRgh/id\GL%}0 8 MAX_PRICE VARCHAR2(4000),
DfpPq3qr0 9 MIN_PRICE VARCHAR2(4000),
2x"zz p ]0 10 PRICE_RATE VARCHAR2(4000)ITPUB个人空间({c}UZBZm
11 );
表已创建。
SQL> CREATE OR REPLACE TRIGGER FIND_ERR_SQLITPUB个人空间rh*o(S+`I
e/j4LyT7~
2 BEFORE INSERT ON SHGOV_ORDERITPUB个人空间#a\Wl2c
3 FOR EACH ROW
'?(ib&w-]+sKp0 4 DECLARE
7ZCL SJ xS1e
{E0 5 PRAGMA AUTONOMOUS_TRANSACTION;
#oz4@k"H'JR0 6 BEGIN
1a:YV#P0B0 7 EXECUTE IMMEDIATE 'INSERT INTO SHGOV_ORDER_BAKITPUB个人空间0`T8z!}5v#gV
8 (
7M"dY.c;M)S0 9 TRADE_RATE, ORDER_AMOUONT, SEND_AMOUNT, RECEIVE_AMOUNT,ITPUB个人空间X_C*I6?
10 UNIT_PRICE, MAX_PRICE, MIN_PRICE, PRICE_RATE
O6vd&H0kz0 11 )
U0v2^?/z&QZ0 12 VALUESITPUB个人空间)^"o'__6Lh
13 (
,_3MXK.D b0 14 ''' || :NEW.TRADE_RATE || ''', ''' || :NEW.ORDER_AMOUONT || ''', '''ITPUB个人空间tx%Z3CX{+C
15 || :NEW.SEND_AMOUNT || ''', ''' || :NEW.RECEIVE_AMOUNT || ''', '''
[*X G"V
RD/r0 16 || :NEW.UNIT_PRICE || ''', ''' || :NEW.MAX_PRICE || ''', '''ITPUB个人空间z*B
`r2O sO
17 || :NEW.MIN_PRICE || ''', ''' || :NEW.PRICE_RATE || ''')';ITPUB个人空间0h*L]y8Jp"^[
18 COMMIT;ITPUB个人空间t%P2tpba
19 END;
"w#P
F
C'c0 20 /
触发器已创建
下面再次执行导致操作,准备从V$SQL中获取异常的数据:
[oracle@bjtest data]$ imp test/test file=jg080424.dmp tables=shgov_order buffer=2048000 ignore=y
Import: Release 9.2.0.4.0 - Production on星期五5月9 21:29:00 2008
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
bY0rdOR0连接到: Oracle9i Enterprise Edition Release 9.2.0.4.0 - 64bit Production
$m
jpdH?8c$@8i0With the Partitioning, OLAP and Oracle Data Mining optionsITPUB个人空间[
z$i&xa%vc
JServer Release 9.2.0.4.0 - Production
经由常规路径导出由EXPORT:V09.02.00创建的文件
警告:此对象由SHGOV导出,而不是当前用户
已经完成ZHS16GBK字符集和AL16UTF16 NCHAR字符集中的导入
}?%~t%w$c$Lr0.正在将SHGOV的对象导入到TEST
7{uh*p6KZ0. .正在导入表 "SHGOV_ORDER" 420835行被导入ITPUB个人空间1Z'^bSC+c _g
IMP-00009:导出文件异常结束
R/l
~4`KT3}0成功终止导入,但出现警告。
另人吃惊的是,导入居然成功了。要知道虽然SHGOV_ORDER_BAK表的数值类型字段全部设置为VARCHAR2(4000),但是SHGOV_ORDER表中仍然为NUMBER类型。
在触发器中直接转化为字符类型会报错,无效的数值,这一点可以参考第一篇文章中的例子,但是Oracle的imp居然成功的将输入插入进去,真是不可思议。
SQL> SELECT COUNT(*) FROM SHGOV_ORDER_BAK;
COUNT(*)
F i,~8I hT,m0----------
l3GE{t4rl{0 420835
SQL> SELECT COUNT(*) FROM SHGOV_ORDER;
COUNT(*)ITPUB个人空间&S4iF&w`_#j
----------
Ae6r2e r `I
@0 420835
SQL> DESC SHGOV_ORDER
RUV1F4x)^wr\ExV0 名称 是否为空?类型
;TS'^0{P/p+b0 ------------------------------------ -------- --------------
K8V ^!h#Ho?1f0 ORDER_ITEM_ID NOT NULL CHAR(24)
T)u
W B
V-iC$H6~a'p0 PLAT_ID CHAR(24)
%c9[$bUz'n^+h0 PRODUCT_ID CHAR(24)ITPUB个人空间!y*F+B"L1ur
CODE VARCHAR2(50)ITPUB个人空间 xn+GRs;MQ
C_NAME_CHN VARCHAR2(300)ITPUB个人空间~hSqEv8l8eq
MEDICAL_ID CHAR(24)
+L9d8z5u;tmh
x0 MEDICAL_CODE VARCHAR2(150)
&K!~g*`kut;f[0 TRADE_NAME VARCHAR2(300)ITPUB个人空间Y~%X
Y"I4W*I,F\7c5N
USE_UNIT VARCHAR2(150)ITPUB个人空间8cMS*e#J"[(b4g4k2c
USED_NAME VARCHAR2(1000)
9}__qz!X0 MANUFACTURE_ID CHAR(24)ITPUB个人空间K5l vfS:k1otC,]+r
MANUFACTURE_NAME VARCHAR2(150)ITPUB个人空间|"|0uV"j4mh5h1I
MANUFACTURE_ABBR VARCHAR2(150)
B8Mgzt^0 M_SPELL_ABBR VARCHAR2(150)ITPUB个人空间VD%WE&pH
vj
STAND_RATE VARCHAR2(150)ITPUB个人空间Y&x"u,L/~:il TI
SPEC VARCHAR2(4000)
#oD0`/cG(Jr'{0 E_NAME_CHN VARCHAR2(150)
-CW%\,TTyi0 JX_NAME_CHN VARCHAR2(150)ITPUB个人空间-y*CIhcJ,h
WRAP_NAME VARCHAR2(150)
I/Is+ny
eA0 TAX_PRICE VARCHAR2(150)ITPUB个人空间X|G)~LT&a
NATIONAL_RETAIL_PRICE VARCHAR2(150)
-~-wN}[$p d0 TRADE_RATE NUMBER
WNV3XBP(TL0 MED_INSURE VARCHAR2(100)ITPUB个人空间K$|]gU9o
ORDER_ID CHAR(24)ITPUB个人空间r!?tf5X
ORDER_AMOUONT NUMBERITPUB个人空间K$Qz/[^3v;g
SEND_AMOUNT NUMBERITPUB个人空间"YU0v.epk*W [C
RECEIVE_AMOUNT NUMBER
+e-RzkN(n+j1?&B0 UNIT_PRICE NUMBERITPUB个人空间,e)j tg3F9q5|$n&w#U
SOURCE_TYPE CHAR(1)
f6u,u }y'V(Tm0 MAX_PRICE NUMBERITPUB个人空间/ny(Djj'agl9G
HIS_NAME VARCHAR2(150)ITPUB个人空间NQ+}we8|*J5a
HIS_ABBR VARCHAR2(50)ITPUB个人空间6mn)k|k7e
HIS_ID CHAR(24)
:EM(Kx-sS0 DEALER_NAME VARCHAR2(150)
~d0WS#N OXXs0 DEALER_ID CHAR(24)ITPUB个人空间2?/oo1u'p ^
DEALER_ABBR VARCHAR2(50)ITPUB个人空间S1o6HF0|SiK
MIN_PRICE NUMBERITPUB个人空间5JA _/~#x;q,U3G1z6R
SENDER_NAME VARCHAR2(150)ITPUB个人空间W~;k\ T
SENDER_ID CHAR(24)
_*Tf3U
[0 SENDER_ABBR VARCHAR2(150)ITPUB个人空间V`W$ZGN&l2_S
CREATE_DATE DATEITPUB个人空间,]R`4| sce:l
SENDE_DATE DATEITPUB个人空间g&] dy\pd+@?,P)~
PRICE_RATE NUMBER
不管怎么说,现在数据已经导入了,检查一下第31323条记录的情况:
SQL> SELECT * FROM (SELECT ROWNUM RN, A.* FROM SHGOV_ORDER_BAK A WHERE ROWNUM < 31324)ITPUB个人空间`Bk fiBI.u`
2 WHERE RN > 31322;
RN
R RrQ:YTW1R0----------