如何理解PosgreSQL中的数字格式

如何理解PosgreSQL中的数字格式,sql,postgresql,formatting,Sql,Postgresql,Formatting,我并没有从PostgreSQL的函数“to_number”中得到我所期望的行为。所以我可能看错了。有没有人能解释一下,这样我就知道在其他类似的情况下会发生什么 -- I find this intuitive: # select to_number( '12,345.67', '99999.999') ; to_number ----------- 12345.67 -- I find this surprising: # select to_number( '12,345.67',

我并没有从PostgreSQL的函数“to_number”中得到我所期望的行为。所以我可能看错了。有没有人能解释一下,这样我就知道在其他类似的情况下会发生什么

-- I find this intuitive:
# select to_number( '12,345.67', '99999.999') ;
 to_number 
-----------
  12345.67

-- I find this surprising:
# select to_number( '12,345.67', '99999.99') ;
 to_number 
-----------
   12345.6

-- EDIT: I found this surprising new variation:
# select to_number( '12,345.67', '999999.99') ;
to_number 
-----------
  12345.67
为什么我的最后一百位数在第二个案例中被删除了

编辑:问题似乎与舍入无关,也与我的格式中小数点右边出现的数字无关。相反,问题与格式包含的字符总数有关,因此与解析的字符总数有关。我认为最终的完整答案将是mu发布的太短内容的一个微小变化

实际上,我总是可以返回比我认为需要的更多的数字。但这不是很令人满意。也许有一天它会咬我。注意:格式中的“9”与“0”不是问题。这些行为与_数相同,我觉得有点奇怪。。。但在上面的链接中有明确的记录。

问题是,您的“数字”有一个逗号作为千位分隔符,但您的模式没有。将它们垂直排列以便于比较:

12,345.67
99999.99
  ^
我们看到模式正在寻找一个数字,但它找到了一个逗号。您的模式与正在使用的字符串不完全匹配,因此会得到意外的结果

如果将分隔符添加到模式中(请参见文档中的内容),则您将获得所需的:

=> select to_number('12,345.67', '99,999.99');
 to_number 
-----------
  12345.67
(1 row)

首先,我要感谢穆。他的回答显然很有帮助。但我现在发布一个单独的答案,因为我认为他所说的答案遗漏了答案的一个重要部分

我没有看过任何PostgreSQL代码,所以我的答案完全来自对其行为的观察。当我创建第一种格式时,我隐式地假设如下:

# My pseudocode for select to_number( '12,345.67', '99999.99') ;
# I guessed PostgreSQL would do this:
1. Parse up to 5 digits
2. [optionally] find a decimal
3. [optionally] if decimal was found, find up to 2 more digits

in this example:
1. Up to five digits: 12345
2. Decimal: yes
3. Two more digits: 67
4. All together: 12345.67

# But in fact what it does is closer to this:
1. Parse up to 8 characters
2. Find the first decimal point in the parsed characters
3. In the set of parsed characters, find up to 5 characters before the decimal 
4. In the set of parsed characters, find up to 2 characters after the decimal.

in this example:
1. Up to 8 characters: 12,345.6
2. First decimal: the penultimate character
3. Before decimal: 12345  
4. After decimal:  6
5. All together: 12345.6
因此,我的问题基本上是,PostgreSQL只解析了8个字符,但我传入了9个字符。因此,解决办法是:

# Mu's suggestion: include comma in the format. Now the format is 9 characters.
# This way it parses all 9 characters:
select to_number('12,345.67', '99,999.99');
 to_number 
-----------
  12345.67

# Or include another character before the decimal
# This way it also parses 9 characters before limiting to 5.2:
select to_number( '12,345.67', '999999.99') ;
 to_number 
-----------
  12345.67

# Or include another character after the decimal
# This way it parses 9 characters before limiting to 5.3:
select to_number( '12,345.67', '99999.999') ;
 to_number 
-----------
  12345.67
一旦你这样看待它,你就会明白为什么不可理解的退化案例会像它们那样起作用:

# like this one work as they do:
select to_number('1x2,3yz45.67', '9999999.9999');
 to_number 
-----------
  12345.67

select to_number('12.3.45.67', '9999999.9999');
 to_number 
-----------
   12.3456

我不确定我是否会指定这样的行为。但现在我们更清楚地看到了我们的期望。

事实上。。。我不同意。您的声明显然是正确的,但随着我进一步测试,我发现了这种变化:
选择to_number('12345.67','999999.99')因此,真正的核心问题不是逗号。我现在要更新这个问题。我现在要这样说:不需要分隔符。相反,我的主要缺点是小数点左边的6个“东西”需要解析。正如你所建议的,它可以是5-9加上一个分隔符。或者,它可以是小数点左边的6 9,以强制考虑完整字符串。PostgreSQL 11今天发布。根据模式中的分隔符将不再使用数字。因此,PostgreSQL将开始像我预期的那样运行。很不错的。