ORA-01400:奇怪的行为

gui*_*i42 5 oracle null insert

Oracle Database 11g企业版11.2.0.3.0版 - 64位生产

A,B,C和D是VARCHAR2

E是DATE

(A,B,C,D,E)是TABLEDESTINATION的主要关键

truncate table TABLEDESTINATION;

INSERT  /*+ parallel(10) */  INTO TABLEDESTINATION (A,B,C,D, E)
  SELECT
    TABLE1.DATA1,
    TABLE2.DATA2,
    TABLE2.DATA3,
    NVL(TABLE3.DATA4, '-') DATA4,
    TRUNC(TABLE1.DATA_DATE ,'MONTH') DATA_DATE
  FROM TABLE1 
    INNER JOIN TABLE2 ON TABLE1.DATA1 = TABLE2.DATA1 AND TABLE1.Z = TABLE2.Z
    LEFT JOIN TABLE3 ON TABLE1.X=TABLE3.X
  GROUP BY 
    TABLE1.DATA1,  TABLE2.DATA2, TABLE2.DATA3, 
    NVL(TABLE3.DATA4, '-'),  TRUNC(TABLE1.DATA_DATE ,'MONTH');
Run Code Online (Sandbox Code Playgroud)

将导致"ORA-01400:无法插入NULL("USER"."TABLEDESTINATION"."E")"

现在,如果我使用完全相同的查询,但使用临时表:

truncate table TABLEDESTINATION;

CREATE TABLE TEST_TABLE AS
  SELECT
    TABLE1.DATA1,
    TABLE2.DATA2,
    TABLE2.DATA3,
    NVL(TABLE3.DATA4, '-') DATA4,
    TRUNC(TABLE1.DATA_DATE ,'MONTH') DATA_DATE
  FROM TABLE1 
    INNER JOIN TABLE2 ON TABLE1.DATA1 = TABLE2.DATA1 AND TABLE1.Z = TABLE2.Z
    LEFT JOIN TABLE3 ON TABLE1.X=TABLE3.X
  GROUP BY 
    TABLE1.DATA1, TABLE2.DATA2, TABLE2.DATA3, 
    NVL(TABLE3.DATA4, '-'),  
    TRUNC(TABLE1.DATA_DATE ,'MONTH');

INSERT  /*+ parallel(10) */  INTO TABLEDESTINATION (A,B,C,D, E)
  select DATA1,DATA2,DATA3, DATA4, DATA_DATE
  from TEST_TABLE;
Run Code Online (Sandbox Code Playgroud)

正确插入行,没有任何错误.

现在我尝试相同的查询,但使用日期的NVL:

INSERT  /*+ parallel(10) */  INTO TABLEDESTINATION (A,B,C,D, E)
  SELECT
    TABLE1.DATA1,
    TABLE2.DATA2,
    TABLE2.DATA3,
    NVL(TABLE3.DATA4, '-') DATA4,
    /* -> */ NVL(TRUNC(TABLE1.DATA_DATE ,'MONTH'), SYSDATE) /* <- */ DATA_DATE
  FROM TABLE1 
    INNER JOIN TABLE2 ON TABLE1.DATA1 = TABLE2.DATA1 AND TABLE1.Z = TABLE2.Z
    LEFT JOIN TABLE3 ON TABLE1.X=TABLE3.X
  GROUP BY 
    TABLE1.DATA1,  TABLE2.DATA2, TABLE2.DATA3, 
    NVL(TABLE3.DATA4, '-'),  
    /* -> */ NVL(TRUNC(TABLE1.DATA_DATE ,'MONTH'), SYSDATE) /* <- */
  ;
Run Code Online (Sandbox Code Playgroud)

正确插入行,没有任何错误.

从逻辑上讲,这意味着我在DATA_DATE中有NULL值:

SELECT
  TABLE1.DATA1,
  TABLE2.DATA2,
  TABLE2.DATA3,
  NVL(TABLE3.DATA4, '-') DATA4,
  NVL(TRUNC(TABLE1.DATA_DATE ,'MONTH'), SYSDATE) DATA_DATE
FROM TABLE1 
  INNER JOIN TABLE2 ON TABLE1.DATA1 = TABLE2.DATA1 AND TABLE1.Z = TABLE2.Z
  LEFT JOIN TABLE3 ON TABLE1.X=TABLE3.X
WHERE 
  TABLE1.DATA_DATE IS NULL
;
Run Code Online (Sandbox Code Playgroud)

返回0行

SELECT
  TABLE1.DATA1,
  TABLE2.DATA2,
  TABLE2.DATA3,
  NVL(TABLE3.DATA4, '-') DATA4,
  NVL(TRUNC(TABLE1.DATA_DATE ,'MONTH'), SYSDATE) DATA_DATE
FROM TABLE1 
  INNER JOIN TABLE2 ON TABLE1.DATA1 = TABLE2.DATA1 AND TABLE1.Z = TABLE2.Z
  LEFT JOIN TABLE3 ON TABLE1.X=TABLE3.X
WHERE 
  TRUNC(TABLE1.DATA_DATE) IS NULL
;
Run Code Online (Sandbox Code Playgroud)

返回0行

怎么可能在DATA_DATE中没有NULL值但是Oracle却抛出了一个ORA-01400?

如何使用临时表,使用完全相同的查询,我没有得到相同的错误?

编辑:像建议,我也尝试使用DISTINCT:

INSERT  /*+ parallel(10) */  INTO TABLEDESTINATION (A,B,C,D, E)
  SELECT DISTINCT
    TABLE1.DATA1,
    TABLE2.DATA2,
    TABLE2.DATA3,
    NVL(TABLE3.DATA4, '-') DATA4,
    TRUNC(TABLE1.DATA_DATE ,'MONTH') DATA_DATE
  FROM TABLE1 
    INNER JOIN TABLE2 ON TABLE1.DATA1 = TABLE2.DATA1 AND TABLE1.Z = TABLE2.Z
    LEFT JOIN TABLE3 ON TABLE1.X=TABLE3.X
Run Code Online (Sandbox Code Playgroud)

返回以下错误:ORA-12805:并行查询服务器意外死亡

编辑2:如果我删除并行提示,我收到此错误:" ORA-00001:违反了唯一约束(ZRA.ZRAQX_VENTE_DOPR_MOIS_PK2) "我仍然不明白,因为我在主键上使用GROUP BY,我没有任何NULL值......

EDIT3:我尝试使用隐式游标:

FOR CURTEST IN (/* same select as above */) LOOP
INSERT INTO TABLEDESTINATION (A,B,C,D,E) values (CURTEST.DATA1,CURTEST.DATA2,CURTEST.DATA3,CURTEST.DATA4, CURTEST.DATA_DATE);
END LOOP;
Run Code Online (Sandbox Code Playgroud)

而且意外:它有效!没有错误.

没有任何意义了......

gui*_*i42 0

我找到了错误的根源:

TRUNC(TABLE1.DATA_DATE ,'MONTH') DATA_DATE
Run Code Online (Sandbox Code Playgroud)

如果我用这个代替:

TRUNC(TABLE1.DATA_DATE ,'MM') DATA_DATE
Run Code Online (Sandbox Code Playgroud)

有用 !

一个月后我能够重现该错误。

所以这确实是 Oracle 的 TRUNC 和“MONTH”错误

谢谢大家的建议。