【问题标题】:Oracle: Invalid number error on join between varchar columnsOracle:连接 varchar 列时出现无效数字错误
【发布时间】:2023-02-22 04:22:21
【问题描述】:

我有一个包含非常冗长查询的过程。当我运行过程时,一个特定的连接给我一个“ORA-01722:无效数字”错误。这是加入:

from adv.hr_giving_ag_cash g
left join aga_allocation_handling ah on ah.allocation_code = g.alloc_code 

如果我注释掉连接线,错误就会消失。有几个令人费解的事情:

  • 我加入的两个字段(ah.allocation_code 和 g.alloc_code)都是 varchar 类型,并且没有空行或空行。因此,没有必要涉及数字。
  • 如果我将查询从过程中复制出来并自行执行,则不会发生错误。

此外,没有从 aga_allocation_handling 表中选择任何内容。最终我会在 where 子句中使用它,但现在它被注释掉了。

我什至不知道如何开始调试它。有人对我有什么想法吗?谢谢!

【问题讨论】:

  • 如果在过程外部运行查询有效的事实应该是问题可能来自周围而不是查询内部的线索。只有 2 行并不能使您的问题成为最小的可重现示例。
  • 应该完整获取独立查询的结果(因此我使用 CTAS 或 select max(col1), ..., max(colN) from (<your query>) 来确保这一点)。否则,它将返回数据中可能有或没有问题的前 N ​​行。如果您将这两列显式转换为字符串会怎样:to_char(ah.allocation_code) = to_char(g.alloc_code)?
  • 作为一种调试技术:使用查询结果创建中间表并将 g.alloc_code 添加到输出中。然后在上面写一个 PL/SQL 循环分类带有 left join 到 aga_allocation_handling 打印获取行数的中间表(行内容在这里无关紧要)。它将为您提供失败行的序号位置,您可以手动验证
  • @astentx 我已经尝试将 to_char 添加到两列,但我仍然收到错误。我明白你关于查询只返回前 N 行的观点,我将检查在获取所有行时是否发生错误。
  • 正如我的猜测,您的问题不是由该特定连接引起的。我认为 join 只会改变你的查询结果,这可能会导致其他比较表达式/类型转换变得无效(例如,NULL 数据值)

标签: sql oracle stored-procedures


【解决方案1】:

确定你的错误在哪里。你需要一个错误回溯。这通常是在向调用者引发异常时为您提供的,但您可能会捕获它并且看不到完整的堆栈。尝试手动发出它,以便您可以调试,如下所示:

DECLARE
  CURSOR cur_whatever IS
  SELECT ... ;
BEGIN
  /* open your cursor, fetch through it, etc.. */
EXCEPTION
  WHEN OTHERS THEN
    dbms_output.put_line(NVL(dbms_utility.format_error_backtrace,SQLERRM));
    dbms_output.put_line(dbms_utility.format_error_stack);
    dbms_output.put_line(dbms_utility.format_call_stack);
END;

错误回溯是最重要的一个。使用它在您的代码中找到抛出异常的正确行号。如果它在 PL/SQL 中的某处,应该很容易识别问题。如果它报告您的 SQL(或 OPEN 游标调用)的起始行号,那么问题可能出在 SQL 本身。如果是这种情况,请将 SQL 拉出或放入一个新的过程中并对其进行解构,直到您发现问题为止。

如果确定错误出在 SQL 中并且您可以在过程外成功运行 SQL(直到完成,而不是直到您开始看到行返回),请确保:

  1. 所有绑定变量都替换为正确的值
  2. 您正在以拥有该过程的同一用户身份运行(以消除您可能会遇到具有相同名称的不同对象的可能性)
  3. 执行计划在外部和内部是相同的。您需要从 dbms_plan.display_cursor([sql_id]) 获取在 proc 中运行的那个。希望它解析成功,所以它有一个计划。与您的独立版本(EXPLAIN PLAN FOR... 然后是dbms_plan.display)进行比较。如果连接顺序不同,这实际上会导致数字错误的出现或消失,具体取决于需要将哪些内部转换函数应用于特定数据,这些数据可能会或可能不会被后续连接过滤掉。尝试使用提示强制执行原始连接顺序,直到匹配为止,看看是否可以重现错误。

    这些只是一些调试思路。

【讨论】:

    【解决方案2】:

    请查看哪一列是哪种数据类型。 看到这一点:

    select *
    from user_tab_columns tc
    where table_name in (upper('hr_giving_ag_cash'),upper('aga_allocation_handling')) and
      column_name in (upper('allocation_code'),upper('alloc_code'))
    

    您很可能正在将数字列与 varchar2 列进行比较。因此,查看上面的选择返回的内容将 to_char() 应用于数字列,这应该可以解决错误。虽然,如果您必须将数字列与 varchar2 列进行比较,我认为数据库设计存在根本性错误。一般来说你应该比较

    【讨论】:

    • 我在我的问题中明确指出两列都是 varchar2 类型。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-01
    • 1970-01-01
    • 2013-08-31
    • 2011-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多