使用static / constant ON子句时出现奇怪的MERGE行为

时间:2014-09-18 13:10:44

标签: sql oracle11g merge-statement

CREATE TABLE test (c1 NUMBER(10) NOT NULL);

exec DBMS_ERRLOG.CREATE_ERROR_LOG ( 'test', 'err_test');

我想在表test中插入其他表中的一些值,并记录错误。我还想记录无法插入到err_test表中的记录的ID。在伪代码中,这将导致类似这样的事情:

INSERT INTO test(c1)
SELECT some_nr AS special_nr FROM some_table_which_has_an_unique_id_for_each_number
LOG ERRORS INTO err_test('Could not insert record with id:' || some_table.id /* where id is the id number of the special_nr */ ) REJECT LIMIT UNLIMITED;

上述情况显然无效,因为src.id未知。但我可以使用合并语句执行上面的插入, 作为插入语句:

MERGE INTO test trg
USING (SELECT NULL AS special_nr, 17 AS id FROM DUAL ) src
ON      (1 = 2) -- force INSERTS (!!) Not using INSERT statement because in err log extra data is needed.
WHEN NOT MATCHED THEN 
        INSERT  (trg.c1)
        VALUES  (src.special_nr)
LOG ERRORS INTO err_test('Could not insert record with id:' || src.id) REJECT LIMIT UNLIMITED;

执行上述操作后,错误不会记录在err_table中,而是会返回给用户:

    ORA-01489: result of string concatenation is too long
    ORA-01400: cannot insert NULL into ("SCV_DPN"."TEST"."C1")

字符串太长了?然后我尝试没有err_mesg $:

中的连接
MERGE INTO test trg
USING (SELECT NULL AS special_nr, 17 AS id FROM DUAL ) src
ON      (1 = 2) -- force INSERTS (!!) Not using INSERT statement because in err log extra data is needed.
WHEN NOT MATCHED THEN 
        INSERT  (trg.c1)
        VALUES  (src.special_nr)
LOG ERRORS INTO err_test(src.id) REJECT LIMIT UNLIMITED;

奥赫:

    ORA-38908: internal error occurred during DML Error Logging
    ORA-01024: invalid datatype in OCI call
    ORA-01400: cannot insert NULL into ("SCV_DPN"."TEST"."C1")      

变得更好:

MERGE INTO test trg
USING (SELECT NULL AS special_nr, 17 AS id FROM DUAL ) src
ON      (1 = 2) -- force INSERTS (!!) Not using INSERT statement because in err log extra data is needed.
WHEN NOT MATCHED THEN 
        INSERT  (trg.c1)
        VALUES  (src.special_nr)
LOG ERRORS INTO err_test('Could not insert record with id:' || nvl(src.id, -1)) REJECT LIMIT UNLIMITED;

现在我被踢了:

    ORA-03113: end-of-file on communication channel
    Process ID: 25352
    Session ID: 171 Serial number: 979  

这里发生了什么?似乎1 = 2是罪魁祸首,因为

MERGE INTO test trg
USING (SELECT NULL AS special_nr, 17 AS id FROM DUAL ) src
ON      (src.id IS NULL) -- force INSERTS (!!) Not using INSERT statement because in err log extra data is needed.
WHEN NOT MATCHED THEN 
        INSERT  (trg.c1)
        VALUES  (src.special_nr)
LOG ERRORS INTO err_test('Could not insert record with id:' || src.id) REJECT LIMIT UNLIMITED;

按预期工作,并且(!!)在err_table

中记录错误
    ORA_ERR_NUMBER$     ORA_ERR_MESG$                                                   ORA_ERR_ROWID$  ORA_ERR_OPTYP$  ORA_ERR_TAG$                            C1
    1400                ORA-01400: cannot insert NULL into ("SCV_DPN"."TEST"."C1")                      I               Could not insert record with id:17          

现在它没有问题。

有人可以向我解释这里发生了什么和/或为解决上述问题提供了更好的方法,其中源表中的额外信息必须记录在ORA_ERR_MESG$字段中。 /强>

注意:根据documentation,我可以使用1 = 2要将所有源行插入表中,可以在ON子句条件中使用常量过滤谓词。常量过滤谓词的示例是ON(0 = 1)。

1 个答案:

答案 0 :(得分:1)

我相信你错过了一个可能的罪魁祸首:在tag参数中包含一个行值。我不相信此功能旨在提供您尝试使用它的功能。虽然我找不到任何相关的文档,但对初始merge(具有连接错误的那个)的简单更改似乎证实了这一点:

MERGE INTO test trg
USING (SELECT NULL AS special_nr, 17 AS id FROM DUAL ) src
ON      (1 = 2) -- force INSERTS (!!) Not using INSERT statement because in err log extra data is needed.
WHEN NOT MATCHED THEN 
        INSERT  (trg.c1)
        VALUES  (src.special_nr)
LOG ERRORS INTO err_test('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx') REJECT LIMIT UNLIMITED;

尽管标记超过了最初提供的连接值的长度,但此SQL仍然成功。

为了获得您想要的更详细的日志记录,我建议使用包含插入的游标循环。它可能稍慢,但它可以让您记录尽可能多的细节,因为当您出现错误时。


documentation似乎支持这一结论,尽管它比直接说明的更为隐含。在描述"简单表达"允许错误记录,它指出:"表达式可以是文本文字,数字文字或一般的SQL表达式,如绑定变量。"