“ON CONVERSION ERROR”失败并显示“ORA-43918:此参数必须是文字”

Jon*_*ler 2 oracle oracle12c

ON CONVERSION ERROR应允许转换函数处理诸如“ORA-01858:在需要数字的地方发现非数字字符”之类的错误。但是当我使用该功能时,我只会收到不同的错误:

SQL> select to_date(the_date default null on conversion error, 'MM/DD/YYYY') the_date
  2  from
  3  (
  4      select '1/1/2021' the_date from dual union all
  5      select 'bad date' the_date from dual
  6  );
select to_date(the_date default null on conversion error, 'MM/DD/YYYY')
                                                           *
ERROR at line 1:
ORA-43918: This argument must be a literal
Run Code Online (Sandbox Code Playgroud)

错误行号和列号没有意义,因为代码已经使用了文字。

Jon*_*ler 6

游标_共享

当参数 CURSOR_SHARING 设置为 FORCE 时,该ON CONVERSION ERROR功能不起作用。要避免此错误,请更改系统、会话或语句级别的参数。

理想情况下,整个系统的 CURSOR_SHARING 应设置为 EXACT。但是如果我们有一个不使用绑定变量的应用程序,我们可能无法运行alter system set cursor_sharing=exact;

可以使用 来在会话级别设置参数alter session set cursor_sharing=exact;,但不断更改会话参数并不总是很方便。

可以使用提示在语句级别更改参数CURSOR_SHARING_EXACT

SQL> select /*+ cursor_sharing_exact */ to_date(the_date default null on conversion error, 'MM/DD/YYYY') the_date
  2  from
  3  (
  4      select '1/1/2021' the_date from dual union all
  5      select 'bad date' the_date from dual
  6  );

THE_DATE
---------
01-JAN-21
Run Code Online (Sandbox Code Playgroud)

解析器/优化器错误

正如 @gouessej 发现的那样,ORA-43918 错误还有另一个与游标共享无关的潜在原因。某些版本的 Oracle 上似乎存在与转换CASE和函数相关的解析或优化器错误。TO_

例如,以下 SQL 语句在 Oracle 18c 和 19c 上失败:

SQL> select case when v_num is null then 0 else v_num end
  2  from
  3  (
  4      select to_number('120.3' default null on conversion error, '99999D99') as v_num
  5      from dual
  6  );
    select to_number('120.3' default null on conversion error, '99999D99') as v_num
                                                               *
ERROR at line 4:
ORA-43918: This argument must be a literal
Run Code Online (Sandbox Code Playgroud)

我相信这是一个解析或优化器错误,因为如果您通过添加诸如 之类的谓词来停止转换,错误就会消失rownum >= 1。(当 Oracle 看到 时ROWNUM,它假定结果必须按特定顺序显示,并且不会对该查询块应用尽可能多的转换。)

SQL> select case when v_num is null then 0 else v_num end
  2  from
  3  (
  4      select to_number('120.3' default null on conversion error, '99999D99') as v_num
  5      from dual
  6  where rownum >= 1
  7  );

CASEWHENV_NUMISNULLTHEN0ELSEV_NUMEND
------------------------------------
                               120.3
Run Code Online (Sandbox Code Playgroud)