具有填充模式的Oracle to_char格式编号(FM0000)

时间:2015-09-23 08:31:43

标签: sql oracle

我使用TO_CHAR函数格式化从00019999的数字,并使列大小(VARCHAR2(4))适合插入值(即使值是> 9999)。

我使用这样的功能:

TO_CHAR(n, 'FM0000')

有效的例子:

SELECT TO_CHAR(1, 'FM0000') FROM DUAL;

结果0001

SELECT TO_CHAR(1234, 'FM0000') FROM DUAL;

结果1234

但是当我使用大于9999的值测试时,我会得到一个额外的字符

SELECT TO_CHAR(12345, 'FM0000') FROM DUAL;

结果#####

SELECT TO_CHAR(123456, 'FM0000') FROM DUAL;

结果#####

有关信息,我预期的结果是####(在4个字符上)。

总结一下:

  • 当要转换的值对应于预期大小(4)时,转换后的值具有相同的长度(4)
  • 当要转换的值超过预期大小(5或更多)时,转换后的值比预期长度(5)多一个字符。

如何解释这个?

我没有在Oracle文档https://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements004.htm#i170559

中找到解释

我尝试了几个Oracle版本(9,10,11),结果是一样的。

我找到的

解决方法是使用RPAD()函数RPAD(TO_CHAR(n,'FM0000'), 4)截断结果,但我需要理解为什么TO_CHAR函数不够。

1 个答案:

答案 0 :(得分:11)

您的格式模型仍然必须允许值的符号。没有办法向TO_CHAR()表明它永远不会是负面的(如果你的价值实际上就是这种情况)。即使使用4位数字,格式化允许允许五个字符,您可以从列标题中看到:

SQL> SELECT TO_CHAR(1234, 'FM0000') FROM DUAL;

TO_CH
-----
1234

注意列标题​​是TO_CH,它是五个字符,而不是四个字符。如果您有一个负数(如Florin所建议的那样),您需要额外的空间:

SQL> SELECT TO_CHAR(-1234, 'FM0000') FROM DUAL;

TO_CH
-----
-1234

如果没有FM修饰符,您会在返回的字符串中获得正值的前导空格,因此LENGTH(TO_CHAR(1234, '0000'))为5但LENGTH(TO_CHAR(1234, 'FM0000'))为4,因为前导空格(通常会使列右对齐的值被抑制。如果为负值,则返回字符串的长度为5。格式模型确定返回的数据类型为varchar2(5)允许用于符号,即使您知道永远不会有负值 - 格式模型也没有任何方法可以反映出来。

如果你强制显示标志,你也可以看到正值:

SQL> SELECT TO_CHAR(1234, 'FMS0000') FROM DUAL;

TO_CH
-----
+1234

TO_CHAR电话中,您无法做任何事情。作为RPAD解决方法的替代方法,您可以使用SUBSTR仅获取格式化字符串的最后四个字符:

SQL> SELECT SUBSTR(TO_CHAR(12345, 'FM0000'), -4) FROM DUAL

SUBSTR(TO_CHAR(1
----------------
####

但如果你确实有负值,你就会失去这个标志:

SQL> SELECT SUBSTR(TO_CHAR(-1234, 'FM0000'), -4) FROM DUAL

SUBSTR(TO_CHAR(-
----------------
1234

使用你的RPAD,你保留了标志,但失去了第四位数字:

SQL> SELECT RPAD(TO_CHAR(-1234, 'FM0000'), 4) FROM DUAL

RPAD(TO_CHAR(-12
----------------
-123

这也不好。你可能不必处理负数;但如果您处理的数字大于预期(即,当您只期望< = 9999时,您得到的数字> = 10000)那么我不确定您是否可以确定您不会看到(无效?)在某些时候的负数。无论如何,这似乎是一个数据问题,而不是格式问题。

根据你对Ollie的评论,另一种可能对代码的未来维护者更明确和明显的方法是在CASE中拼写出来:

SELECT CASE WHEN n BETWEEN 0 AND 9999 THEN TO_CHAR(n, 'FM0000') ELSE '####' END FROM DUAL

如果您愿意,还可以将字符串列留空或使用其他魔法值而不是####

另一种修剪价值的方法,即可能也更清晰,就是CAST:

SQL> SELECT CAST(TO_CHAR(12345, 'FM0000') AS VARCHAR2(4)) FROM DUAL;

CAST
----
####