一个ORA-604错误的分析

同事碰到一个ORA-604错误,分析了一下发觉还比较有趣,简单记录一下。

 

 

出错的SQL大致如下:

SQL> CREATE TABLE T_604 AS
  2  SELECT * FROM
  3  (SELECT OBJECT_TYPE, TO_CHAR(AVG(OBJECT_ID), '999999.999') FROM DBA_OBJECTS
  4  GROUP BY OBJECT_TYPE
  5  ORDER BY 2 DESC)
  6  WHERE ROWNUM < 10;
(SELECT OBJECT_TYPE, TO_CHAR(AVG(OBJECT_ID), '999999.999') FROM DBA_OBJECTS
                                                                *
3 行出现错误:
ORA-00604:
递归 SQL 1 出现错误
ORA-01401:
插入的值对于列过大

由于同事并不是DBA,因此对这个错误比较困惑,他不清楚为什么SELECT语句执行没有任何的问题,而根据SELECT的查询结果去创建表就发生了错误,因此同事任何可能是空间分配上出了问题。

SQL> SELECT * FROM
  2  (SELECT OBJECT_TYPE, TO_CHAR(AVG(OBJECT_ID), '999999.999') FROM DBA_OBJECTS
  3  GROUP BY OBJECT_TYPE
  4  ORDER BY 2 DESC)
  5  WHERE ROWNUM < 10;

OBJECT_TYPE        TO_CHAR(AVG
------------------ -----------
DATABASE LINK
MATERIALIZED VIEW    31618.000
RULE SET             31581.400
DIMENSION            31414.000
DIRECTORY            31207.667
EVALUATION CONTEXT   29200.091
XML SCHEMA           28358.700
TRIGGER              27552.375
INDEXTYPE            27381.750

已选择9行。

一般来说,ORA-604错误很少直接出现在用户调用的SQL中,对于这种情况,后面的那个错误信息是真正引发错误的原因。

所以这里引发错误的真正原因是后面的那个ORA-1401错误。这个错误不难理解,插入的值比列的定义要大。

不过CREATE TABLE AS SELECT无法为创建表的列指定数据类型和长度限制,数据类型和长度都由SELECT的查询结果来确定。按照道理就不应该会出现这种错误。

其实问题很简单,导致错误的真正原因是列名长度太长了,只需要将上面的CREATE TABLE语句改变一下写法,就可以顺利执行了:

SQL> CREATE TABLE T_604 (OBJECT_TYPE, AVG_OBJECT_ID) AS
  2  SELECT * FROM
  3  (SELECT OBJECT_TYPE, TO_CHAR(AVG(OBJECT_ID), '999999.999') FROM DBA_OBJECTS
  4  GROUP BY OBJECT_TYPE
  5  ORDER BY 2 DESC)
  6  WHERE ROWNUM < 10;

表已创建。

SQL> DROP TABLE T_604;

表已删除。

SQL> CREATE TABLE T_604 AS
  2  SELECT * FROM
  3  (SELECT OBJECT_TYPE, TO_CHAR(AVG(OBJECT_ID), '999999.999') AVG_OBJECT_ID
  4  FROM DBA_OBJECTS
  5  GROUP BY OBJECT_TYPE
  6  ORDER BY 2 DESC)
  7  WHERE ROWNUM < 10;

表已创建。

当用户执行DDL操作时,Oracle通过大量的递归调用来维护数据字典。比如这个CREATE TABLE语句,Oracle就会更新TAB$COL$等表。这些操作都是递归调用操作,而在递归调用过程中出现的错误,就会报错ORA-604

由于没有指定别名,Oracle试图将TO_CHAR(AVG(OBJECT_ID), '999999.999')作为列名,而这个的长度显然超过了列长度30的限制,因此Oracle在插入数据字典表的时候报错ORA-1401错误。

这个错误的产生还有一定的条件,如果是TO_CHAR(AVG(OBJECT_ID), '999999.999')直接出现在SELECT的外层,在CREATE TABLE的时候,Oracle会明确要求用户提供别名:

SQL> CREATE TABLE T_604 AS
  2  SELECT OBJECT_TYPE, TO_CHAR(AVG(OBJECT_ID), '999999.999')
  3  FROM DBA_OBJECTS
  4  GROUP BY OBJECT_TYPE
  5  ORDER BY 2 DESC;
SELECT OBJECT_TYPE, TO_CHAR(AVG(OBJECT_ID), '999999.999')
                    *
2 行出现错误:
ORA-00998:
必须使用列别名命名此表达式

 

 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/4227/viewspace-374849/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/4227/viewspace-374849/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值