考虑到数据库服务器上定义的NLS\U数字字符,如何使用correclty to_NUMBER()Oracle函数?

考虑到数据库服务器上定义的NLS\U数字字符,如何使用correclty to_NUMBER()Oracle函数?,oracle,function,internationalization,nls,Oracle,Function,Internationalization,Nls,今天,我发现OracleNLS\u数字\u字符的定义模棱两可 事实上,从一开始,我就认为NLS\u NUMERIC\u CHARACTERS仅用于定义十进制数字的显示方式 但实际上,NLS\u NUMERIC\u CHARACTERS在TO\u NUMBER()函数中也隐式使用,以定义要转换的字符串编号的格式 我的问题是,我是欧洲人,对我来说,十进制分隔符实际上是逗号(,)而不是点() 当我显示一个数字时,我的首选是使用逗号来显示它。因此,NLS\u NUMERIC\u CHARACTERS设置

今天,我发现Oracle
NLS\u数字\u字符的定义模棱两可

事实上,从一开始,我就认为
NLS\u NUMERIC\u CHARACTERS
仅用于定义十进制数字的显示方式

但实际上,
NLS\u NUMERIC\u CHARACTERS
TO\u NUMBER()
函数中也隐式使用,以定义要转换的字符串编号的格式

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

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

到目前为止,我对此没有任何问题:-)

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

当我将转换任何表示数字的字符串值时,我可以使用下面的函数对Oracle函数进行编号

select TO_NUMBER(VALUE) from TB_PARAMETER;
select TO_NUMBER(VALUE
                ,'999999999D999999999'
                ,'NLS_NUMERIC_CHARACTERS = ''.,'''
                )
  from TB_PARAMETER;
如果十进制分隔符是一个点(
NLS\u NUMERIC\u CHARACTERS=”,“
),则此操作非常有效,但如果十进制分隔符是逗号(
NLS\u NUMERIC\u CHARACTERS=”,“,”,“
),则此操作停止

我知道我可以在
TO\u NUMBER()
函数中指定
NLS\u NUMERIC\u字符

select TO_NUMBER(VALUE) from TB_PARAMETER;
select TO_NUMBER(VALUE
                ,'999999999D999999999'
                ,'NLS_NUMERIC_CHARACTERS = ''.,'''
                )
  from TB_PARAMETER;
但这对我来说太冗长了

是否有一个Oracle函数可以做同样的事情?

例如:

select CAST_NUMBER(VALUE) from TB_PARAMETER;
就我个人而言,我认为Oracle
TO_NUMBER()
函数使用
NLS\u NUMERIC\u CHARACTERS
会话的参数来定义要转换的十进制字符串的格式是一个错误

实际上,在数据库中,字符串中使用的小数分隔符总是固定的。它是一个逗号或一个点,但从来没有,一次是一个逗号,另一次是一个点

如果我的分析是正确的,
TO_NUMBER()
函数必须始终使用一个固定值,该值是一个点或逗号,在所有情况下都与NLS_NUMERIC_字符不对应,因为此参数具有会话范围,并且由Oracle客户端应用程序定义

在resume中,当您在Oracle视图中使用
TO_NUMBER()
函数而不指定任何
NLS_数字字符
时,您的视图将正常工作,直到它在具有另一个不同
NLS_数字字符
值的会话中执行为止

当您尝试使用Oracle
将保存为字符串的日期值转换为_DATE()
函数时,同样的情况肯定存在

为什么是模棱两可的

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

在会话级别或系统级别更改NLS_数字_字符并不总是可能的,因为NLS_数字_字符有两个不同的角色或目标

  • 固定十进制数字的十进制分隔符显示
  • 正在修复用于将字符串转换为_NUMBER()的十进制分隔符 作用
  • 示例:假设您将创建一个显示十进制数字的视图,并使用TO_NUMBER()进行一些计算

    如果数据库中保存的十进制分隔符为点,并且需要使用逗号作为十进制分隔符来显示十进制数,则可以更改NLS_数字_字符以将十进制分隔符定义为点。Oracle TO_NUMBER()函数将正确工作,但屏幕上显示的十进制数将以点作为十进制分隔符显示

    这就是为什么我说NLS_数字_字符是不明确的

    在resume中,在一个数据库系统中,NLS_数值_字符可以是“.”、“.”或“,.”,并且十进制数可以使用固定格式保存在Oracle表中(例如:十进制分隔符是POINT),如果不指定正确的NLS_数值_字符,则使用to_number()是不安全的


    Oracle的错误(或者误解,如果您愿意的话)是定义了一个参数(NLS\u数字\u字符)和两个不同的角色

    在我看来,最好的选择是将数字保留在
    NUMBER
    数据类型列中。您将如何将
    应用于_NUMBER
    value='32.5rzg'


    除此之外,我假定您已经发现(应用
    NLS\u数字字符
    )除了使用
    替换
    并将这些字符串值中的所有点转换为逗号之外,您还可以做些什么

    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';
    

    我将明确指出,我们使用带有名称和值字段的TB_参数表(为了保持简单)。该值定义为VARCHAR2(200),可以包含字符串、数字、整数和日期。这种技术在保存参数方面非常常见。另一种技术是定义类型字段,并添加具有相应类型的整数值、数值、日期值字段。问题是我不负责TB_参数表的定义。我要补充的是,您的解决方案(使用REPLACE(“.”、“,”)只适用于一个选择,我可以在SqlPlus或SqlDeveloper中键入,但不适用于任何用户都可以执行的视图!啊,参数。。。我明白,我已经看到了同样的原理,将所有内容存储到同一个VARCHAR2列中。考虑更改表并指定该值的“实际”数据类型。创建一个返回特定参数值的函数。根据“真实”数据类型指示符,使用适当的格式掩码应用不同的函数(到\u编号、到\u日期等)。换句话说,不要每次需要从TB_参数表中获取某些内容时都写入SELECT,而是使用函数。是的,我使用的函数已在下一个答案中解释过。好的,就是这样,对吗?解决了的?因为,如果您仍然希望一些内置的Oracle函数能够做到这一点