考虑到在数据库服务器上定义的NLS_NUMERIC_CHARACTERS,如何使用正确的TO_NUMBER()Oracle函数?

时间:2018-08-22 07:45:51

标签: oracle function internationalization nls

今天,我发现Oracle NLS_NUMERIC_CHARACTERS的定义不明确!

确实,从一开始,我就认为NLS_NUMERIC_CHARACTERS仅用于定义十进制数字的显示方式。

但是实际上,NLS_NUMERIC_CHARACTERS函数中也隐式使用TO_NUMBER()来定义要转换的STRING编号的格式。

我的问题是我是欧洲人,对我来说,小数点分隔符实际上是逗号(,),而不是点(。)。

当我显示一个数字时,我的首选是使用逗号显示它。因此,NLS_NUMERIC_CHARACTERS设置为',.',其中第一个字符定义数字分隔符。

直到现在,我都没问题:-)

我的问题是所有String表字段的值都包含数字,都使用POINT字符作为小数点分隔符。

当我将任何表示数字的字符串值转换时,可以使用TO_NUMBER Oracle函数,

select TO_NUMBER(VALUE) from TB_PARAMETER;

如果小数点分隔符为POINT(NLS_NUMERIC_CHARACTERS = '.,'),则效果很好;但如果小数点分隔符为COMMA(NLS_NUMERIC_CHARACTERS = ',.',则停止工作。

我知道我可以像这样在NLS_NUMERIC_CHARACTERS函数中指定TO_NUMBER()

select TO_NUMBER(VALUE
                ,'999999999D999999999'
                ,'NLS_NUMERIC_CHARACTERS = ''.,'''
                )
  from TB_PARAMETER;

但这对我来说很冗长!

是否存在执行相同功能的Oracle函数?

示例:

select CAST_NUMBER(VALUE) from TB_PARAMETER;

过时的,我认为Oracle TO_NUMBER()函数使用NLS_NUMERIC_CHARACTERS会话的参数来定义要转换的十进制字符串格式的事实是 bug

实际上,在数据库中,字符串中使用的小数点分隔符始终是固定的。它是逗号或一点,但绝不是逗号,一次是点。

如果我的分析是正确的,则TO_NUMBER()函数必须始终使用一个固定值,即POINT或COMMA(在所有情况下都不与NLS_NUMERIC_CHARACTERS对应),因为此参数具有会话范围并已定义通过Oracle客户端应用程序。

在简历中,当您在Oracle视图中使用TO_NUMBER()函数而不指定任何NLS_NUMERIC_CHARACTERS时,您的视图将保持正确性,直到在具有另一个不同的NLS_NUMERIC_CHARACTERS的会话中执行该视图为止值!

当您尝试使用Oracle TO_DATE()函数转换保存为字符串的DATE值时,肯定存在同样的事情!

为什么模棱两可!

为回答评论中的一些问题,我在以下段落中添加了我的详细解释。

由于在NLS_NUMERIC_CHARACTERS具有两个不同的角色或目标,因此在会话级别或系统级别更改NLS_NUMERIC_CHARACTERS并不总是可能的。

  1. 固定十进制数字的小数分隔符显示
  2. 固定用于在TO_NUMBER()中转换字符串的小数点分隔符 功能

示例:假设您将创建一个显示十进制数字并使用TO_NUMBER()进行计算的视图。

如果保存在数据库中的小数点分隔符为POINT,并且有必要使用COMMA作为小数点分隔符显示小数点,则可以更改NLS_NUMERIC_CHARACTERS以将小数点分隔符定义为POINT。 Oracle TO_NUMBER()函数将正确运行,但屏幕上显示的十进制数字将以POINT作为十进制分隔符显示!

这就是为什么我说NLS_NUMERIC_CHARACTERS不明确。

在简历中,在数据库系统中NLS_NUMERIC_CHARACTERS可以为“。”或“。”。 AND,可以使用固定格式(例如:小数点分隔符为POINT)将十进制数保存在Oracle表中,使用TO_NUMBER()而不指定正确的NLS_NUMERIC_CHARACTERS是不安全的。

Oracle错误(或者您可能会误解)是定义了具有两个不同角色的参数(NLS_NUMERIC_CHARACTERS)!

2 个答案:

答案 0 :(得分:3)

从我的角度来看,最好的选择是将数字保留在for i in range(1,20): a = a.replace('TABLESPACE "D'+str(i).zfill(2)+'"','TABLESPACE COPY_TBS') 数据类型列中。您如何将NUMBER应用于TO_NUMBER

除此之外,我想您已经发现(应用value = '32.5rzg')是可以做的,除了使用NLS_NUMERIC_CHARACTERS并在所有字符串值中将所有点都转换为逗号之外。

答案 1 :(得分:1)

有关信息,我创建了关注函数

CREATE FUNCTION TO_X_NUMBER(sNumber IN VARCHAR2) 
  RETURN NUMBER as

BEGIN
    RETURN TO_NUMBER
        (sNumber
        ,'99999999999999999999D99999999999999999999'
        ,'NLS_NUMERIC_CHARACTERS=''.,''');
END TO_X_NUMBER;

和同义词

CREATE PUBLIC SYNONYM TO_X_NUMBER FOR GWHDBA.TO_X_NUMBER; 

GRANT EXECUTE ON TO_X_NUMBER TO PUBLIC; 

我现在可以从另一个架构中使用它,如以下示例所示:

SELECT TO_X_NUMBER(PARAM_VALUE) as STANDARD_DEVIATION
  FROM TB_PARAMETER
  WHERE PARAM_NAME = 'STANDARD_DEVIATION';