为什么Oracle不告诉你缺少哪个表或视图?

66
如果您使用过 Oracle,您可能会得到一个有用的信息: "ORA-00942: 表或视图不存在"。这个错误信息没有包含缺少的对象名称,这是否有合法的技术原因?
关于这个错误信息不包含表名的争论听起来像是由TSA制定的。如果我是攻击者,我会知道我刚刚尝试利用哪个表,并且能够轻松地解释这个无用的消息。如果我是一个开发人员,在应用程序代码的多层复杂连接中工作,通常很难确定。
我的猜测是当实现此错误时,有人忽略了添加对象名称,现在人们害怕修复它会破坏兼容性。(做一些傻事情比如解析错误消息的代码会困惑于它所更改的内容。)
有没有一种开发人员友好(而不是招募DBA)的方法来确定缺少表的名称?
虽然我接受了一个与主题相关的答案,但它并没有真正回答我的问题:为什么错误消息不包含名称? 如果有人能提出真正的答案,我将很乐意改变我的投票。

3
我想你需要问一个真正的Oracle工程师来得到真正的答案。顺便说一下,我在Sybase工作,我们的服务器(SQL Anywhere)会给你“表'blah'未找到”的信息。 - Graeme Perrow
3
可能是出于保密惯性的原因 ;) : 链接 - James P.
8
我完全同意发帖者的观点。因为Oracle没说哪个表不存在,我试图找到开发问题花费了好几个小时!而且安全性呢?你仍然可以选择不向客户传递详细错误信息,通常你是永远不会这么做的!当涉及到超出显而易见的思考时,我通常认为Oracle的软件真的很糟糕... - Lawrence
8个回答

14
您可以在参数文件(纯文本或 spfile)中设置 EVENT,以强制 Oracle 在 user_dump_dest 中转储详细跟踪文件,对象名称可能在其中,如果没有,则应该是 SQL。
EVENT="942 trace name errorstack level 12"
如果您使用的是纯文本文件,则需要将所有 EVENT 设置保持在连续的行上。不确定这如何适用于 spfile。

我尝试将这行代码添加到“init.ora”文件中,然后重新启动了我的DBMS,但是在user_dump_dest文件夹中没有任何内容可用。请问有什么提示吗? - user1389591

12

SQL*Plus 会告诉你找不到的表。例如:

SQL> select
  2     *
  3  from
  4     user_tables a,
  5     non_existent_table b
  6  where
  7     a.table_name = b.table_name;
   non_existent_table b
   *
ERROR at line 5:
ORA-00942: table or view does not exist

这里显示了缺失表的名称以及SQL语句中出错行的行号。

同样,在一行SQL语句中,您可以看到星号突出显示未知表的名称:

SQL> select * from user_tables a, non_existent_table b where a.table_name = b.table_name;
select * from user_tables a, non_existent_table b where a.table_name = b.table_name
                             *
ERROR at line 1:
ORA-00942: table or view does not exist

就您的问题而言,我猜测错误信息没有包含表名的原因是因为该错误消息本身需要成为静态文本。错误所在行号和位置将清楚地传递回SQL * Plus(以某种方式)。


7
当您可以使用SQL* Plus进行交互式测试查询时,这是很好的。然而,常见情况是,您仅拥有一个应用程序使用Hibernate等持久层所生成的日志,很难准确地确定执行了哪个查询。 - erickson
2
@erickson:那更多是Hibernate的问题 ;) (开玩笑的) - Jeffrey Kemp
2
@erickson:恐怕这是薄JDBC驱动程序的限制。OCI调用OCIErrorGet可以返回多个错误字符串。第一个是主要的,其他的是细节(如堆栈跟踪)。您还可以询问“错误处理”以获取诸如OCI_ATTR_PARSE_ERROR_OFFSET之类的详细信息。我在JDBC驱动程序API中找不到任何相应的调用。无论如何,Oracle JDBC驱动程序抛出纯通用的JDBC SqlExption-没有任何Oracle特定的内容。 - ibre5041
1
[ORA-00959 tablespace 'string' does not exist](http://docs.oracle.com/cd/B10501_01/server.920/a96525/e900.htm#1000589) - Amit Naidu

6

我不同意这种观点,认为SQL+无法帮助我们了解哪些表名是不可接受的。当然,在直接DML时它确实有所帮助,但是在动态情况下,它并没有什么帮助:

SQL> begin
  2  execute immediate 'insert into blabla values(1)';
  3  end;
  4  /
begin
*
ERROR at line 1:
ORA-00942: table or view does not exist
ORA-06512: at line 2

5
如果您使用像TOAD或TORA这样的SQL浏览工具,它会通过高亮或将光标移动到错误发生的位置来帮助您解决ORA错误。将您的SQL复制并粘贴到其中一个工具中可以提供帮助。您还可以发现可用的分析信息也很有用。

对我来说,它只是突出显示我定义的常量,例如“:myvar”,所以没有任何帮助。 - adolf garlic

3

我从未遇到过解释Oracle错误信息的问题。部分原因是我看到了为Oracle开发SQL的每个交互式工具都会指向查询出错的位置。这包括SQL*Plus,正如其他人所提到的,以及Perl DBI模块:

$ exec_sql.pl 'select * from daul'
DBD::Oracle::db prepare failed: ORA-00942: table or view does not exist (DBD ERROR: error possibly near <*> indicator at char 14 in 'select * from <*>daul') [for Statement "select * from daul"] at exec_sql.pl line 68.

这段文字有点难读,因为它全部挤在一行上。但是,GUI工具可以指出Oracle在查询中出现问题的标记。如果对解析器进行一些改进,你可以编写一个工具来挑选出错误的表格。

回答潜在的问题,Oracle错误似乎不是按照你期望的方式设计的。就我所知,Oracle中的错误消息都不支持变量文本。相反,Oracle返回两个信息:错误号和错误发生的位置。如果你有适当的工具,用这些数据来诊断错误非常容易。可以说,Oracle的系统比提供根据错误提供可变数量的诊断数据的系统更适合工具创作者。想象一下,如果必须为所有Oracle的错误消息(包括未来的错误)编写自定义解析器来突出显示错误位置,那将会是多么困难。

有时包含表名可能会引起误导。只要知道哪里出了问题,就可以大有帮助:

SQL> select * from where dummy = 'X';
select * from where dummy = 'X'
              *
ERROR at line 1:
ORA-00903: invalid table name

至于为什么Oracle选择这种方式来处理错误消息,我有一些猜测:

  1. IBM在System R中使用了这种风格的错误消息,Larry Ellison、Bob Miner和Ed Oates复制了它们以构建Oracle V2。(向后兼容。)

  2. 错误号和位置是诊断信息的最小表示形式。(简约。)

  3. 如我上面所述,为了简化连接到Oracle的工具的创建。(互操作性。)

无论如何,我认为您不需要成为DBA就能找出哪个表不存在。您只需要使用适当的工具。(并调整您的期望值,我想。)


1
感谢您的输入,Jon。我没有表述清楚,但在我的情况下,这些通常是通过几个不同的代码层在Java应用程序中遇到的...一个Web框架,一个持久性库,Java数据库驱动程序。因此,有时甚至很难确定正在执行哪个查询,特别是如果您正在与另一组合作,以便由第三组创建测试期间的日志!是的,这真是一桶猴子。 - erickson
我会说这更多是对Java而不是Oracle的控诉。;-) - Jon Ericson
1
非常正确。但我从未试图起诉Oracle……除非你把JAVA算作ORCL。尽管有一些怪癖,但就绝对意义而言,Oracle非常出色,并且与“竞争对手”并列时,它看起来更好。 - erickson
1
你不需要成为DBA来找出哪个表,但你确实需要花费时间,看起来没有一个好的理由。 - nsandersen
1
ORA-00904 string: invalid identifier(http://docs.oracle.com/cd/B10501_01/server.920/a96525/e900.htm#206098) - Amit Naidu
我想缩小一个多年增长的查询的大小。我将其复制到另一个地方,删除了一些我认为可以安全删除的内容,现在出现了 ORA-00942: Tabelle oder View nicht vorhanden 00942. 00000 - "table or view does not exist" *Cause: *Action: 的错误提示,没有显示行号或表(或别名)名称。 - Bernhard Döbler

3
如果这不是一个很大的陈述,那么最简单的方法就是检查数据字典。
SQL> select * from xx,abc;
select * from xx,abc
                 *
ERROR at line 1:
ORA-00942: table or view does not exist


SQL> select owner,table_name from all_tables where table_name in ('XX','ABC');

OWNER                          TABLE_NAME
------------------------------ ------------------------------
MWATSON                        XX

SQL> 

这并不是理想的方法,但除了查看跟踪文件之外,我不知道还有什么其他方法可以做到。


3

原因1:多语言界面

对于您的数据库实例,有一个特定于语言的消息配置文件。从中提取消息并将其从纯数字版本翻译成数字+文本版本。

可能认为硬编码字符串比在运行时由于格式不正确的“%s”字符串而冒险导致神秘故障更好。

(顺便说一句,我并不完全同意这个观点。)

原因2:安全性

如果将Oracle错误消息的PHP等转储打印到浏览器上,则不会特别暴露应用程序的内部工作方式。

如果默认情况下打印更详细的信息,则应用程序会更加暴露......例如,如果花旗银行打印更详细的消息。

(请参见上面的免责声明,我也很乐意获得更多错误信息。)


3
ORA-00932 不一致的数据类型: 期望 %s,实际为 %s。 - Amit Naidu

1

@Matthew

你的查询是一个开始,但当你有多个模式时,它可能无法工作。例如,如果我以自己的身份登录我们的实例,我可以读取所有表的访问权限。但是,如果我没有在表名中指定模式,对于没有同义词的表,我将得到ORA-00942错误:

SQL> select * from tools; 
select * from tools 
              * 
ERROR at line 1: 
ORA-00942: table or view does not exist 

该表仍然显示在all_tables中:

SQL> select owner, table_name from all_tables where table_name = 'TOOLS';
OWNER TABLE_NAME ------------------------------ ------------------------------ APPLICATION TOOLS

@erikson 很抱歉这并没有帮助太多。我和Mark一样使用TOAD。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接