9

REAL在 db 中有类型字段。我使用 PostgreSQL。和查询

SELECT * FROM my_table WHERE my_field = 0.15

不返回值为my_fieldis的行0.15

但是例如查询

SELECT * FROM my_table WHERE my_field > 0.15

工作正常。

我怎样才能解决这个问题并获得行my_field = 0.15

4

4 回答 4

17

解决您的问题,请改用数据类型numeric,它不是浮点类型,而是任意精度类型。

如果您将数字文字 0.15输入numeric(相同的单词,不同的含义)列,则会存储确切的数量 - 与realorfloat8列不同,其中值被强制为下一个可能的二进制近似值。这可能准确也可能不准确,具体取决于数量和实施细节。十进制数 0.15 恰好落在可能的二进制表示之间,并且存储时有一个微小的错误。

请注意,计算结果本身可能不精确,因此=在这种情况下仍要警惕运算符。

这也取决于你如何测试。比较时,Postgres 将不同的数字类型强制转换为最能保存结果的类型。考虑这个演示

CREATE TABLE t(num_r real, num_n numeric);
INSERT INTO t VALUES (0.15, 0.15);

SELECT num_r, num_n  
     , num_r = num_n       AS test1           --> FALSE
     , num_r = num_n::real AS test2           --> TRUE
     , num_r - num_n       AS result_nonzero  --> float8
     , num_r - num_n::real AS result_zero     --> real
FROM   t;

db<>fiddle here
sqlfiddle

因此,如果您0.15在 data type 列中输入了数字文字real,则可以通过以下方式找到所有此类行:

SELECT * FROM my_table WHERE my_field = real '0.15'

numeric如果您需要准确存储小数位,请使用列。

于 2013-08-14T16:10:34.653 回答
7

您的问题源于IEEE 754

0.15不是0.15,而是0.15000000596046448(假设双精度),因为它不能精确地表示为二进制浮点数。

检查这个计算器

为什么这是个问题?在这种情况下,很可能是因为比较的另一方使用精确值 0.15 - 通过精确表示,如numeric类型。(根据Eric的建议清除)

所以有两种方法:

  • 使用实际以十进制格式存储数字的格式 - 正如Erwin建议 的那样
    • (或者至少使用相同的类型)
  • 按照杰克的建议使用四舍五入- 必须小心使用(顺便说一下,这numeric也使用了一种类型,以准确表示 0.15...)

推荐阅读: 每个计算机科学家都应该知道的关于浮点运算的知识

(对不起简洁的答案......)

于 2013-08-14T16:09:27.050 回答
2

好吧,我看不到你的数据,但我猜这my_field不完全等于 0.15。尝试:

select * from my_table where round(my_field::numeric,2) = 0.15;
于 2013-08-14T16:07:57.177 回答
1

考虑到 PPTerka 和 Jack 的回答。

Approximate numeric data types do not store the exact values specified for many numbers;

在此处查看 MS 对实际值的描述。

http://technet.microsoft.com/en-us/library/ms187912(v=sql.105).aspx

于 2013-08-14T16:13:10.103 回答