【问题标题】:Oracle to_char format number with fill mode (FM0000)Oracle to_char 格式编号,带填充模式 (FM0000)
【发布时间】:2015-09-23 08:31:43
【问题描述】:

我使用TO_CHAR 函数将数字从0001 格式化为9999,并适应插入值的列大小(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)。

如何解释?

我在 https://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements004.htm#i170559https://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements004.htm#i170559 的 Oracle 文档中没有找到解释

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

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

【问题讨论】:

  • SELECT TO_CHAR(-1, 'FM0000') FROM DUAL;
  • 您到底想达到什么目的?如果您选择大于 9999 的数字(例如 12345),您希望返回什么值?
  • 如果您在 SQL*Plus 中使用 TO_CH。除了您想要的四个有效数字之外,它还必须允许值的符号。 (正如弗洛林的查询所示......)。您也可以尝试使用'FMS000' 来明确查看它的正值。您可以使用 substr(to_char(...), -4) 作为替代解决方法。
  • @Ollie 该值保存在两列中,一列在 VARCHAR2(4) 中(旧系统兼容性),另一列在 NUMBER 中(新系统)。这个想法是让旧系统在 1 到 9999 之间(没有负值)工作,新系统允许大于 9999 的值。在 VARCHAR(4) 列中,值的格式应为 0000,因此值如12345 可以保存为 '####' (在这种情况下它将由新系统处理)。
  • 我现在明白了,TO_CHAR(12345, '0000') 已经返回 #####,所以在这种情况下,FM 将什么也不做,因为没有前导空格。

标签: sql oracle


【解决方案1】:

您的格式模型仍然必须允许值的符号。无法向TO_CHAR() 表明它永远不会是负数(如果您的价值观确实如此)。即使是 4 位数字,格式也允许使用五个字符,正如您从列标题中看到的那样:

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

TO_CH
-----
1234

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

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

TO_CH
-----
-1234

如果没有 FM 修饰符,您会在返回的字符串中获得一个前导空格来表示正值,因此 LENGTH(TO_CHAR(1234, '0000')) 是 5 但 LENGTH(TO_CHAR(1234, 'FM0000')) 是 4,因为前导空格(通常使列中的值正确 - justified) 被压制。对于负值,返回字符串的长度为 5。格式模型确定返回的数据类型是 varchar2(5)allow 作为符号,即使您知道永远不会有负值 - 格式模型没有任何方法可以反映这一点.

如果你强制显示符号,你也可以看到它的正值:

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

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


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

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

如果您愿意,这也允许您将字符串列保留为 null 或使用其他魔法值而不是 ####

另一种修剪值的方法,可能也更清晰,是使用 CAST:

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

CAST
----
####

【讨论】:

    猜你喜欢
    • 2019-11-25
    • 1970-01-01
    • 2018-05-31
    • 1970-01-01
    • 1970-01-01
    • 2018-12-24
    • 1970-01-01
    • 2014-10-22
    • 2023-03-27
    相关资源
    最近更新 更多