【问题标题】:Oracle: elegant way to parse a number to 9,99 formatOracle:将数字解析为 9,99 格式的优雅方式
【发布时间】:2013-07-24 09:17:31
【问题描述】:

使用 Oracle 11g,如果小数的值为 0,我想解析一个数字以去除小数,如果小数的值不同于 0,则在小数分隔符 ',' 后保留两个小数

例子:

1,00 -> 1
1,001 -> 1
0,203 -> 0,20

等等。

我以一种非常不雅的方式获得了类似的东西

select replace(trim(to_char (trunc ('0,2345',2),'9999999990.99')), '.', ',')
from dual

你知道更优雅的方式吗?输出应该是一个字符(不是数字)。

【问题讨论】:

  • 为什么你需要得到不正确的答案,正如你在 cmets 中提到的 AlexPoole 答案?我的意思是,如果你四舍五入,112,999 必须是 113。

标签: oracle numbers format


【解决方案1】:

不确定它是否更优雅,但假设您的替换是处理不同的语言环境,这可能对您有用:

with t as (
  select 1.00 as n from dual
  union all select 1.001 from dual
  union all select 0.203 from dual
  union all select 0.2345 from dual
  union all select 112.999 from dual
)
select n, regexp_replace(to_char(trunc(n, 2), '9999999990D00',
  'NLS_NUMERIC_CHARACTERS='',.'''), '[,.]00$', null) as new_n
from t;

         N NEW_N        
---------- --------------
         1           1    
     1.001           1    
     0.203           0,20 
    0.2345           0,23 
   112.999         112,99 

to_charnls_param 参数让您决定它是使用逗号还是句点作为小数分隔符。如果您可以在会话级别进行设置,那么查询看起来会更简单一些。 regexp_replace 从字符串的末尾删除 ,00(或 .00,认为这是矫枉过正)。


正如 ThinkJet 所指出的,regexp_replace 有点过分,并且由于小数分隔符是在列分类中定义的(并且格式无论如何都没有组分隔符),因此可以通过计划 replace 来完成:

with t as (
  select 1.00 as n from dual
  union all select 1.001 from dual
  union all select 0.203 from dual
  union all select 0.2345 from dual
  union all select 112.999 from dual
  union all select 13.08 from dual
)
select n, replace(trim(
    to_char(trunc(n, 2), '9999999990D00', 'NLS_NUMERIC_CHARACTERS='',.''')),
    ',00', null) as new_n
from t;

         N NEW_N        
---------- --------------
         1 1              
     1.001 1              
     0.203 0,20           
    0.2345 0,23           
   112.999 112,99         
     13.08 13,08          

仍然不确定这是否可以被描述为“优雅”。

【讨论】:

  • @Sam - 我错过了截断。我已经添加并更新了答案以显示该值的结果。
  • @AlexPoole trunc() 结果又错了,试试1.308。必须是round() here。另外,从我的角度来看,使用正则表达式处理这种事情就像使用蒸汽悍马来破解坚果一样。
  • @ThinkJet - 同意您的解码更整洁,尽管它会评估 trunc/round 两次。但是 OP 特别想要 12,99 和 13,08。我最初是让它自然旋转并根据要求添加 trunc。不得不假设 OP 出于某种原因有这个要求。
  • 好的,我向 OP 询问了这个要求。这对我来说看起来很奇怪。
【解决方案2】:

要获得正确的结果,您必须处理数字,而不是字符串:

with t as (
  select 1.00 as n from dual
  union all select 1.001 from dual
  union all select 0.203 from dual
  union all select 0.2345 from dual
  union all select 112.999 from dual
  union all select 112.105 from dual
  union all select 0 from dual
  union all select -12.307 from dual
)
select
  n,
  decode( trunc(n,2) - trunc(n) , 
    0, to_char(trunc(n), 'TM9', 'NLS_NUMERIC_CHARACTERS = '', '''),
    to_char(trunc(n,2),'9999999990D00', 'NLS_NUMERIC_CHARACTERS = '', ''')
  ) 
    string_val  
from t

SQLFiddle

附:更新以获取不正确的截断而不是舍入,如 OP 请求中所示。

【讨论】:

    【解决方案3】:

    另一种变体

    SELECT n,
          to_char( trunc( n, 2 ), 
                   case when mod( trunc( n, 2 ), 1 ) = 0
                        then '9990' 
                        else '9990D00'
                   end, 'NLS_NUMERIC_CHARACTERS='',.''' ) val
    from t
    ;
    


    SQLFiddle demo

    【讨论】:

    • 好的,很好的变种。只是让格式参数更长SQLFiddle
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-18
    • 2012-12-01
    • 2015-10-29
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    相关资源
    最近更新 更多