【问题标题】:Another issue with to_number(). I simply do not understand itto_number() 的另一个问题。我只是不明白
【发布时间】:2011-04-13 07:05:50
【问题描述】:

我有一个主表(以下称为 SURVEY)和一个详细表(以下称为 ANSWERS)。毫不奇怪,ANSWERS 有 SURVEY 问题的答案。 ANSWERS 有一个名为 TEXT 的 VARCHAR2 列。一些 ANSWERS.TEXT 值是真正的文本,但有些实际上是数字。幸运的是,我总是知道哪些行包含文本,哪些包含数字作为文本。

就是这样。我无法改变这一点。

过去,当某些 ANSWERS 行被保存时,它们的 TEXT 值是经过精心挑选的,并被放入正确类型的列中的 SURVEY 表中。一个简单的单表选择将获取 SURVEY 和特殊值。

但是现在,随着新应用程序的添加,我们删除了特殊列。相反,我们现在必须取而代之的是获取适当的 ANSWERS 行的 TEXT 值。

我创建了一个模拟旧的琐碎选择语句的查询。它工作得很好......主要是。

这是一个sn-p:

select survey.*, 
       j2.overall_score
  from survey,
       (select to_number(trim(ANSWER.text)) overall_score, 
               survey.id survey_id 
          from ANSWER, 
               [edited - more SQL that gets the 'score' row from ANSWERS]) j2      
 where
   survey.id=j2.survey_id
   and overall_score > 70    

您可能会注意到 j2.在实际查询中,有六个这样的列,j1 到 j6。当我运行查询时,它看起来 就像旧查询一样。你不能说它真的是由主/细节组装而成的。这是一种解脱!

但是,我的问题是“overall_score > 70”短语会导致“1722 无效数字”错误。当我不包含该短语时,Oracle 就像蛤蜊一样高兴,所以所有输出都通过 j2 的 to_number() 函数并且看起来不错。但是如果我添加条件,我会失败。

where 子句的“overall_score”部分是根据从网页输入的搜索条件动态添加的。

我需要一些 fu 来告诉 Oracle 我真的知道我在做什么,请去做。如果有非数字数据,ok,让j2的to_number()失败。凉爽的。但除此之外,就去做吧。

有什么妙语吗?我是承包商,时间快到了。这是一个新要求:-/

【问题讨论】:

  • 您是否查看过 j2 返回的内容,与最终查询分开?我很难相信您在外部查询中遇到了无效数字错误——我希望 TO_NUMBER 转换会触发错误。
  • 如果我删除 '> 70' 条件,查询返回行。当我添加条件时,我得到 '1722 invalid number' 悲伤。
  • oops 命中返回而不是换行。当我单独运行 j2 子查询时,它返回有效行且没有错误。

标签: sql oracle ora-01722


【解决方案1】:

我认为优化器可能正在将内联视图与查询的其余部分合并,这意味着条件 overall_score > 70 可能会针对与视图的其余谓词不匹配的行进行评估,从而命中符合以下条件的行text 中不包含数值。

如果发生这种情况,您应该能够通过在查询的第一行添加提示来防止它:

select /*+ NO_MERGE(j2) */ ...

或者,它可能会将谓词推送到视图中,在这种情况下,您将需要 NO_PUSH_PRED 提示。如果您可以为查询生成执行计划,它可能会显示确切的问题。

【讨论】:

  • 会的。 DBA 现在正在为我创建一个计划表:-D
  • 解释输出太长,无法发布。我正在使用 oracle 的 UTLXPLS 来查看结果。你用什么?
  • 我创建了不合格查询的视图。然后我从总体得分 > 70 的视图中进行选择。这也失败了。这很奇怪,除非 Oracle 的优化器足够聪明,可以在 select 中使用时优化视图的内部结构。我再次检查了数据,有问题的列始终是“总分”行的数字文本。
  • 添加了 NO_MERGE(j2) 和 NO_PUSH_PRED(j2)(实际上对于所有 j1..6)并得到了相同的结果。
  • 当在更大的选择中使用时,Oracle 会很高兴地优化视图的内部结构。它只是将完整的 SQL 压缩在一起,就好像视图不存在一样 - 视图只是让组装 SQL 的人更容易。
【解决方案2】:

我们创建了一个特殊版本的 to_number,它在内部捕获“1722 无效号码”异常并返回 0 而不是。在 sql 中用这个新函数替换 to_number 为我们解决了这个问题。

【讨论】:

  • 我现在已经死在水里了。我会试一试,但我想如果我的 SQL 是有效的,那么不会有任何杂物通过。
  • 这允许我的查询运行。谢谢。
猜你喜欢
  • 2021-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-30
相关资源
最近更新 更多