考虑到数据库服务器上定义的NLS\U数字字符,如何使用correclty to_NUMBER()Oracle函数?
今天,我发现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设置
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;
就我个人而言,我认为OracleTO_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函数能够做到这一点