考虑到数据库服务器上定义的 NLS_NUMERIC_CHARACTERS,如何使用正确的 TO_NUMBER() Oracle 函数?
How to use correclty TO_NUMBER() Oracle function considering NLS_NUMERIC_CHARACTERS defined on Database server?
今天,我发现 Oracle NLS_NUMERIC_CHARACTERS
定义不明确!
的确,从一开始,我就认为NLS_NUMERIC_CHARACTERS
只是用来定义十进制数的显示方式。
但实际上,NLS_NUMERIC_CHARACTERS
也在TO_NUMBER()
函数中隐式使用来定义要转换的STRING数字的格式。
我的问题是我是欧洲人,对我来说,小数点分隔符实际上是逗号 (,) 而不是点 (.)。
当我显示数字时,我的偏好是使用逗号显示它。为此,NLS_NUMERIC_CHARACTERS
设置为 ',.'
,其中第一个字符定义数字分隔符。
到现在为止,我对此没有问题:-)
我的问题是所有 String
table 的字段值中包含数字的都使用点字符作为小数点分隔符。
当我要转换任何代表数字的字符串值时,我可以使用 TO_NUMBER Oracle 函数,像这样
select TO_NUMBER(VALUE) from TB_PARAMETER;
如果小数点分隔符是点 (NLS_NUMERIC_CHARACTERS = '.,'
),这会很好用,但如果小数点分隔符是逗号 (NLS_NUMERIC_CHARACTERS = ',.'
),这会停止工作。
我知道我可以像这样在 TO_NUMBER()
函数中指定 NLS_NUMERIC_CHARACTERS
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()
函数必须始终使用不对应(在所有情况下)NLS_NUMERIC_CHARACTERS 的固定值,即 POINT 或 COMMA,因为此参数具有一个会话范围,由 Oracle 客户端应用程序定义。
在简历中,当您在 Oracle 视图中使用 TO_NUMBER()
函数而未指定任何 NLS_NUMERIC_CHARACTERS
时,您的视图将正常工作,直到它在具有另一个不同 [=15] 的会话中执行=]价值!
当您尝试使用 Oracle TO_DATE()
函数转换保存为字符串的 DATE 值时,同样的事情肯定存在!
为什么是模棱两可的!
为了回答评论中的一些问题,我在下面的段落中添加了我的长篇解释。
在会话级别或系统级别更改 NLS_NUMERIC_CHARACTERS 并不总是可行的,因为 NLS_NUMERIC_CHARACTERS 有 2 个不同的角色或目标。
- 修复十进制数字的小数分隔符显示
- 固定用于在 TO_NUMBER() 中转换字符串的小数点分隔符
函数
示例:假设您将创建一个显示小数的视图,并使用 TO_NUMBER() 进行一些计算。
如果数据库中保存的小数点分隔符是POINT,需要显示小数点时使用COMMA作为小数点分隔符,可以修改NLS_NUMERIC_CHARACTERS定义小数点分隔符为POINT。 Oracle TO_NUMBER() 函数将正常工作,但屏幕上显示的小数将以 POINT 作为小数点分隔符显示!
这就是为什么我说 NLS_NUMERIC_CHARACTERS 是模棱两可的。
在简历中,在 NLS_NUMERIC_CHARACTERS 可以是 '.,' 或 ',.' 的数据库系统中并且十进制数可以使用固定格式保存在 Oracle table 中(例如:小数点分隔符是 POINT)使用 TO_NUMBER() 而不指定正确的 NLS_NUMERIC_CHARACTERS 是不安全的。
Oracle 错误(如果您愿意,也可以是误解)是定义了一个具有 2 个不同角色的参数 (NLS_NUMERIC_CHARACTERS)!
好吧,在我看来,最好的选择是将数字保留在 NUMBER
数据类型列中。您将如何将 TO_NUMBER
应用到 value = '32.5rzg'
?
除此之外,我认为您已经发现的(应用 NLS_NUMERIC_CHARACTERS
)是您可以做的,除了使用 REPLACE
并将这些字符串值中的所有点都转换为逗号。
作为参考,我已经创建了跟随函数
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';
今天,我发现 Oracle NLS_NUMERIC_CHARACTERS
定义不明确!
的确,从一开始,我就认为NLS_NUMERIC_CHARACTERS
只是用来定义十进制数的显示方式。
但实际上,NLS_NUMERIC_CHARACTERS
也在TO_NUMBER()
函数中隐式使用来定义要转换的STRING数字的格式。
我的问题是我是欧洲人,对我来说,小数点分隔符实际上是逗号 (,) 而不是点 (.)。
当我显示数字时,我的偏好是使用逗号显示它。为此,NLS_NUMERIC_CHARACTERS
设置为 ',.'
,其中第一个字符定义数字分隔符。
到现在为止,我对此没有问题:-)
我的问题是所有 String
table 的字段值中包含数字的都使用点字符作为小数点分隔符。
当我要转换任何代表数字的字符串值时,我可以使用 TO_NUMBER Oracle 函数,像这样
select TO_NUMBER(VALUE) from TB_PARAMETER;
如果小数点分隔符是点 (NLS_NUMERIC_CHARACTERS = '.,'
),这会很好用,但如果小数点分隔符是逗号 (NLS_NUMERIC_CHARACTERS = ',.'
),这会停止工作。
我知道我可以像这样在 TO_NUMBER()
函数中指定 NLS_NUMERIC_CHARACTERS
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()
函数必须始终使用不对应(在所有情况下)NLS_NUMERIC_CHARACTERS 的固定值,即 POINT 或 COMMA,因为此参数具有一个会话范围,由 Oracle 客户端应用程序定义。
在简历中,当您在 Oracle 视图中使用 TO_NUMBER()
函数而未指定任何 NLS_NUMERIC_CHARACTERS
时,您的视图将正常工作,直到它在具有另一个不同 [=15] 的会话中执行=]价值!
当您尝试使用 Oracle TO_DATE()
函数转换保存为字符串的 DATE 值时,同样的事情肯定存在!
为什么是模棱两可的!
为了回答评论中的一些问题,我在下面的段落中添加了我的长篇解释。
在会话级别或系统级别更改 NLS_NUMERIC_CHARACTERS 并不总是可行的,因为 NLS_NUMERIC_CHARACTERS 有 2 个不同的角色或目标。
- 修复十进制数字的小数分隔符显示
- 固定用于在 TO_NUMBER() 中转换字符串的小数点分隔符 函数
示例:假设您将创建一个显示小数的视图,并使用 TO_NUMBER() 进行一些计算。
如果数据库中保存的小数点分隔符是POINT,需要显示小数点时使用COMMA作为小数点分隔符,可以修改NLS_NUMERIC_CHARACTERS定义小数点分隔符为POINT。 Oracle TO_NUMBER() 函数将正常工作,但屏幕上显示的小数将以 POINT 作为小数点分隔符显示!
这就是为什么我说 NLS_NUMERIC_CHARACTERS 是模棱两可的。
在简历中,在 NLS_NUMERIC_CHARACTERS 可以是 '.,' 或 ',.' 的数据库系统中并且十进制数可以使用固定格式保存在 Oracle table 中(例如:小数点分隔符是 POINT)使用 TO_NUMBER() 而不指定正确的 NLS_NUMERIC_CHARACTERS 是不安全的。
Oracle 错误(如果您愿意,也可以是误解)是定义了一个具有 2 个不同角色的参数 (NLS_NUMERIC_CHARACTERS)!
好吧,在我看来,最好的选择是将数字保留在 NUMBER
数据类型列中。您将如何将 TO_NUMBER
应用到 value = '32.5rzg'
?
除此之外,我认为您已经发现的(应用 NLS_NUMERIC_CHARACTERS
)是您可以做的,除了使用 REPLACE
并将这些字符串值中的所有点都转换为逗号。
作为参考,我已经创建了跟随函数
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';