Oracle - 为什么转换为TO_CHAR时数字的前导零消失

con*_*att 36 sql oracle oracle10g

在Oracle中,当将具有前导零的数字转换为字符时,为什么前导数字会消失?这个逻辑是Oracle特定的,还是特定于SQL?

例:

SELECT TO_CHAR(0.56) FROM DUAL;
/* Result = .56 */
Run Code Online (Sandbox Code Playgroud)

Vad*_*zim 31

我正在寻找一种格式化数字的方法,没有前导或尾随空格,句点,零(除了一个前导零,小于1的数字应该存在).

令人沮丧的是,在Oracle中无法轻松实现这种最常见的格式化.

甚至Tom Kyte也建议使用这样的长期复杂的解决方法:

case when trunc(x)=x
    then to_char(x, 'FM999999999999999999')
    else to_char(x, 'FM999999999999999.99')
end x
Run Code Online (Sandbox Code Playgroud)

但我能够找到更短的解决方案,只提到一次价值:

rtrim(to_char(x, 'FM999999999999990.99'), '.')
Run Code Online (Sandbox Code Playgroud)

适用于所有可能的值:

select 
    to_char(num, 'FM99.99') wrong_leading_period,
    to_char(num, 'FM90.99') wrong_trailing_period,
    rtrim(to_char(num, 'FM90.99'), '.') correct
from (
  select num from (select 0.25 c1, 0.1 c2, 1.2 c3, 13 c4, -70 c5 from dual)
  unpivot (num for dummy in (c1, c2, c3, c4, c5))
) sampledata;

    | WRONG_LEADING_PERIOD | WRONG_TRAILING_PERIOD | CORRECT |
    |----------------------|-----------------------|---------|
    |                  .25 |                  0.25 |    0.25 |
    |                   .1 |                   0.1 |     0.1 |
    |                  1.2 |                   1.2 |     1.2 |
    |                  13. |                   13. |      13 |
    |                 -70. |                  -70. |     -70 |
Run Code Online (Sandbox Code Playgroud)

仍在寻找更短的解决方案.

有自定义帮助函数的缩短审批:

create or replace function str(num in number) return varchar2
as
begin
    return rtrim(to_char(num, 'FM999999999999990.99'), '.');
end;
Run Code Online (Sandbox Code Playgroud)

但是自定义pl/sql函数具有显着的性能开销,不适合繁重的查询.

  • 为了获得更多的小数位和自定义分隔符,我使用了`RTRIM(TO_CHAR(x,'FM999999999999990D99999999999999','NLS_NUMERIC_CHARACTERS ='',.'''),',')`.这是捷克语语言环境中使用的格式. (2认同)
  • @FrancescoPegoraro,它们是小数点和千位分隔符,按此顺序。1.000,000 在我国读作“千”,保留三位小数,但在英语国家读作“一”,保留小数点后六位。https://datacadamia.com/db/oracle/nls_numeric_characters (2认同)

DCo*_*kie 30

这是Oracle提供的默认格式.如果要在输出上使用前导零,则需要明确提供格式.使用:

SELECT TO_CHAR(0.56,'0.99') FROM DUAL;
Run Code Online (Sandbox Code Playgroud)

甚至:

SELECT TO_CHAR(.56,'0.99') FROM DUAL;
Run Code Online (Sandbox Code Playgroud)

尾随零也是如此:

SQL> SELECT TO_CHAR(.56,'0.990') val FROM DUAL;

VAL
------
 0.560
Run Code Online (Sandbox Code Playgroud)

TO_CHAR转换函数的一般形式是:

TO_CHAR(数字,格式)

  • 当我们没有小数点后的确切位数时,会出现此解决方案的问题.在这种情况下我们能做些什么?一个非常丑陋的解决方案是添加一个`case,当myNum <1然后addLeadingZero end case`并对-1和0之间的数字做同样的事情.那么......我们能做什么? (6认同)
  • 请查看http://ss64.com/ora/syntax-numfmt.html以获取有关不同数字格式的良好列表 (4认同)
  • 为了我之前的评论(超过3年前),我只需要添加以下内容:rtrim(to_char('。45','0.9999999999999'),'0')将返回'0.45',这就是我们在寻找开始 (2认同)
  • 这个答案太具体了(对于一种特殊情况),不应该是最高投票的。例如,@Vadzim 和其他人的答案既涵盖了 OP 的情况,也涵盖了较大数字的其他各种情况。 (2认同)

mkb*_*mkb 7

似乎在漂亮(对我来说)形式中获取小数的唯一方法需要一些荒谬的代码.

到目前为止我唯一的解决方案:

CASE WHEN xy>0 and xy<1 then '0' || to_char(xy) else to_char(xy)
Run Code Online (Sandbox Code Playgroud)

xy 是一个十分之一.

xy             query result
0.8            0.8  --not sth like .80
10             10  --not sth like 10.00
Run Code Online (Sandbox Code Playgroud)

如果有真正的格式选项,请回答这个问题.


raw*_*rto 5

这仅适用于小于 1 的数字。

select to_char(12.34, '0D99') from dual;
-- Result: #####
Run Code Online (Sandbox Code Playgroud)

这行不通。

你可以做这样的事情,但这会导致领先的空格:

select to_char(12.34, '999990D99') from dual;
-- Result: '     12,34'
Run Code Online (Sandbox Code Playgroud)

最终,您可以添加一个 TRIM 来再次去除空格,但我也不认为这是一个合适的解决方案......

select trim(to_char(12.34, '999990D99')) from dual;
-- Result: 12,34
Run Code Online (Sandbox Code Playgroud)

同样,这仅适用于最多 6 位的数字。

编辑:我想将此添加为对 DCookie 建议的评论,但我不能。