SelectInsertのデバッグがメンドイとき

SelectInsertするときにInsert先のテーブルにPK、UK、FK、NOTNULL制約などが張ってあって
Insertに失敗すると結構ストレスがたまります。
そもそもどのレコードで失敗したのかわからなかったりすると
NotNullだったらSelectのWhereにIS NOT NULLかいて探したり
UKだったら GROUP HAVING 書いて探したり
かなりめんどくさいので10gからはdbms_errlogパッケージ使ってレコード特定してます。
http://otndnld.oracle.co.jp/document/products/oracle10g/102/doc_cd/appdev.102/B19245-02/d_errlog.htm

つかいかた例:

  • Insert先にUKが張ってあり、Select元で重複が発生している状態

select元テーブル

CREATE TABLE SELECT_TABLE
(
    NAME                           VARCHAR2(10)
);

select_tableデータ

NAME
a
b
c
d
e
f
a
g
h

insert先テーブル

CREATE TABLE INSERT_TABLE
(
    NAME                           VARCHAR2(10),
    CONSTRAINT UK_INSERT_TABLE UNIQUE (NAME) USING INDEX
)

上記の状態でSelectInsert

INSERT INTO INSERT_TABLE(NAME) SELECT NAME FROM SELECT_TABLE;

すると、「ORA-00001: unique constraint violated.」と一意制約違反で失敗しますが
どのレコードで失敗したかは自分で下記のようなSQLでSelectしてこないとわかりません。

SELECT
	NAME
	,COUNT(*)
FROM
	SELECT_TABLE
GROUP BY
	NAME
HAVING
	COUNT(*) > 1;

がんばってデバッグするのも大変なので
まずdbms_errlogパッケージのcreate_error_logプロシージャを呼び出します。

exec dbms_errlog.create_error_log('INSERT_TABLE');

このプロシージャを呼ぶとエラー行保持テーブルが作成されます。

CREATE TABLE NIWANO.ERR$_INSERT_TABLE
(
    ORA_ERR_NUMBER$                NUMBER,
    ORA_ERR_MESG$                  VARCHAR2(2000),
    ORA_ERR_ROWID$                 UROWID,
    ORA_ERR_OPTYP$                 VARCHAR2(2),
    ORA_ERR_TAG$                   VARCHAR2(2000),
    NAME                           VARCHAR2(4000)
)
/

次に先ほどのSelectInsertの最後にLOG ERRORS INTOをつけます。

INSERT INTO INSERT_TABLE(NAME) SELECT NAME FROM SELECT_TABLE
LOG ERRORS INTO ERR$_INSERT_TABLE('SelectInsertで失敗した') REJECT LIMIT 10;

すると、SelectInsertは失敗しませんが、ERR$_INSERT_TABLEに下記のようにエラーレコードが入ります。

ORA_ERR_NUMBER$ ORA_ERR_MESG$ ORA_ERR_ROWID$ ORA_ERR_OPTYP$ ORA_ERR_TAG$ NAME
1 "ORA-00001: 一意制約(UK_INSERT_TABLE)に反しています" I SelectInsertで失敗した a

これをみれば NAME=a のレコードでInsertが失敗したことがわかり、さらにInsert可能行はすべてInsertされます。

ちなみにLOG ERRORSの内容は
LOG ERRORS INTO エラーログ格納テーブル名('エラータグ名') REJECT LIMIT エラー許容件数;
って感じです。


今回のようにSQLデバッグにも活用できますし、SQLでエラー行はスキップしてInsertしたい場合などにも
使えると思いますのでOracle10gの環境が近くにある方は使ってみるとストレスから解放されるかもしれません。