【问题标题】:Oracle - Why does the leading zero of a number disappear when converting it TO_CHAROracle - 为什么将数字转换为 TO_CHAR 时数字的前导零会消失
【发布时间】:2011-10-05 10:53:08
【问题描述】:

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

例子:

SELECT TO_CHAR(0.56) FROM DUAL;
/* Result = .56 */

【问题讨论】:

    标签: sql oracle oracle10g


    【解决方案1】:

    似乎以漂亮(对我而言)形式获得小数的唯一方法需要一些荒谬的代码。

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

    CASE WHEN xy>0 and xy<1 then '0' || to_char(xy) else to_char(xy)
    

    xy 是一个小数。

    xy             query result
    0.8            0.8  --not sth like .80
    10             10  --not sth like 10.00
    

    【讨论】:

      【解决方案2】:

      如果数字是这样的,请尝试以下格式

      ex 1 假设像 10.1 这样的数字,如果应用以下格式,它将是 10.10

      ex 2 假设像 .02 这样的数字,如果应用以下格式,它将是 0.02

      ex 3 假设像 0.2 这样的数字,如果应用以下格式,它将是 0.20

      to_char(round(to_number(column_name)/10000000,2),'999999999990D99') as column_name

      【讨论】:

        【解决方案3】:

        应该适用于所有情况:

        SELECT regexp_replace(0.1234, '^(-?)([.,])', '\10\2') FROM dual
        

        【讨论】:

          【解决方案4】:

          这是 Oracle 提供的默认格式。如果您希望输出前导零,则需要明确提供格式。使用:

          SELECT TO_CHAR(0.56,'0.99') FROM DUAL;
          

          甚至:

          SELECT TO_CHAR(.56,'0.99') FROM DUAL;
          

          尾随零也是如此:

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

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

          TO_CHAR(号码,format)

          【讨论】:

          • 查看ss64.com/ora/syntax-numfmt.html 了解可用的不同数字格式的良好列表
          • 这个解决方案的问题是当我们没有小数点后的确切位数时。在这种情况下我们能做什么?一个非常丑陋的解决方案是添加 case when myNum &lt; 1 then addLeadingZero end case 并对 -1 和 0 之间的数字执行相同的操作。那么......我们能做什么?
          • 为了我之前的评论(3年前),我只需要添加这个: rtrim(to_char('.45', '0.9999999999999'), '0') 将返回'0.45',这是我们一开始所寻找的
          • 这个答案太具体了(对于一种特殊情况),不应该是最受好评的。例如,@Vadzim 和其他人的回答既涵盖了 OP 的情况,也涵盖了其他各种更大数字的情况。
          • @EduCastrillon 这正是我想要的,谢谢!
          【解决方案5】:

          尝试这样做以避免 to_char 限制:

          SELECT 
          regexp_replace(regexp_replace(n,'^-\'||s,'-0'||s),'^\'||s,'0'||s)
          FROM (SELECT -0.89 n,RTrim(1/2,5) s FROM dual);
          

          【讨论】:

          • 使用两个 regex_replace 对我来说看起来非常不理想。最初的问题是为什么?,而不是如何?
          • 这比 to_char 好,因为你不限于特定的格式。对于大数,您可以转义 ####### 情况,而对于整数,您可以在小数点后转义不需要的零。它只是为在本地 Oracle 表示中看起来很尴尬的 [-1;1] 范围数字添加了零。如果您确定该数字是正数,则只需一个 regexp_replace 就足够了。
          【解决方案6】:

          我正在寻找一种方法来格式化数字,而不用前导或尾随 spaces、句点、零(除了应该存在的小于 1 的数字的前导零)。

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

          即使Tom Kyte only suggested long complicated workaround 是这样的:

          case when trunc(x)=x
              then to_char(x, 'FM999999999999999999')
              else to_char(x, 'FM999999999999999.99')
          end x
          

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

          rtrim(to_char(x, 'FM999999999999990.99'), '.')
          

          works as expected 表示所有可能的值:

          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 |
          

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

          有一个带有自定义辅助函数的缩短方法:

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

          但是custom pl/sql functions have significant performace overhead 不适合繁重的查询。

          【讨论】:

          • 这对我帮助很大。谢谢
          • 为了获得更多的小数位和自定义分隔符,我使用了RTRIM(TO_CHAR(x, 'FM999999999999990D99999999999999', 'NLS_NUMERIC_CHARACTERS = '',.'''), ',')。这是捷克语言环境中使用的格式。
          • @Palec 你能解释一下 NLS_NUMERIC_CHARACTERS = '',.''' 的字符和含义吗?
          • @FrancescoPegoraro,它们是十进制和千位分隔符,按此顺序。 1.000,000 在我的国家读作小数点后三位的一千,但在英语国家读作小数点后六位的一千。 datacadamia.com/db/oracle/nls_numeric_characters
          【解决方案7】:

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

          select to_char(12.34, '0D99') from dual;
          -- Result: #####
          

          这行不通。

          您可以这样做,但这会导致前导空格:

          select to_char(12.34, '999990D99') from dual;
          -- Result: '     12,34'
          

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

          select trim(to_char(12.34, '999990D99')) from dual;
          -- Result: 12,34
          

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

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

          【讨论】:

            猜你喜欢
            • 2017-08-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-05-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多