我遇到了一个基本的MySQL查询令人困惑的问题。
这是我的表:
id | rating
1 | 1317.17
2 | 1280.59
3 | 995.12
4 | 973.88
现在,我正在尝试查找rating
列大于某个值的所有行。如果我尝试以下查询:
SELECT * FROM (`users`) WHERE `rating` > '995.12'
它正确返回2
。
但是,如果我尝试
SELECT * FROM (`users`) WHERE `rating` > '973.88'
它返回4
!所以就好像它认为表中的973.88大于973.88,但它与995.12没有同样的错误。无论我是从PHP脚本还是在phpMyAdmin中运行查询,都会发生这种情况。
有什么想法吗?
答案 0 :(得分:17)
这是因为您决定使用浮点数据类型而导致的后果。浮子不准确。这意味着:是的,您可以产生> a = true
例如,你的第四行:
mysql> SELECT * FROM t WHERE id=4; +------+--------+ | id | rating | +------+--------+ | 4 | 973.88 | +------+--------+ 1 row in set (0.00 sec)
我已经发布了您已发布的数据类型FLOAT
。我们在这里:
mysql> SELECT rating>973.88 FROM t WHERE id=4; +---------------+ | rating>973.88 | +---------------+ | 1 | +---------------+ 1 row in set (0.00 sec)
糟糕!
为什么呢?要理解为什么会这样,你应该意识到如何表示浮点数据类型。长篇大论是here。但是 - 我将简要介绍一下。
在此处如何表示:其中:
s
是标志b
基础。它的含义与 radix e
是指数。 这意味着我们可以用不同的方式表示一个数字 - 这取决于我们选择的基数。最常见的是b=2
。但并非所有实数都可以用这个基数精确表示,即使在十进制基数中它们看起来很好"。着名的例子是0.1
- 它不能精确地表示在b=2
中 - 因此它被大致存储。同样,长篇故事你可以看到here - 但我只是注意到,用基数2精确地表示它是不可能的。
结果是:即使数字在十进制基数中是精确的,仍然可能无法精确地表示它 - 因此,它将被大致存储。它是如何工作的,事实上,这是意图 - 因为浮动本身的结构。
固定精度
嗯,首先,你应该问问自己:你真的需要漂浮吗?注意:我说:浮动。因为 - 还有固定点数。它们将以固定精度表示数字。说起来容易:使用定点数据类型,您可以确定您将准确存储您在屏幕上看到的内容。因此,如果它是973.88
- 那么它是973.88
而不是973.8800000439234
。转向交易:
mysql> ALTER TABLE t CHANGE rating rating DECIMAL(8,2); Query OK, 4 rows affected, 4 warnings (0.47 sec) Records: 4 Duplicates: 0 Warnings: 4
和..
mysql> SELECT rating>973.88 FROM t WHERE id=4; +---------------+ | rating>973.88 | +---------------+ | 0 | +---------------+ 1 row in set (0.00 sec)
TADA!魔术发生了。您的号码现在以固定的精度存储,因此,此类比较失败。
使用float
然后,可能当你遇到浮动时有用例(但是,在DBMS的情况下,我很难记住即使是这样一个用途 - case - 如果不是大量计算的情况,可能会对性能产生影响,请参阅下面的说明)。然后还有一种方法可以让它发挥作用。您应该决定适合您的精度。那就是:从哪一点开始,你将数字视为等于。
您只存储了两位有效数字,因此我认为1E-5
的精确度已经足够了。然后,您的查询将如下所示:
mysql> set @eps=1E-5; Query OK, 0 rows affected (0.00 sec)
并将其用于:
SELECT * FROM t WHERE rating>973.88+@eps
将导致
+------+---------+ | id | rating | +------+---------+ | 1 | 1317.17 | | 2 | 1280.59 | | 3 | 995.12 | +------+---------+
哪个更好?
要实现这一点,您需要再次查看封面。我简要概述了float
数据类型是什么以及为什么它不准确。但是,fixed
数据类型也有它的弱点。可能不是我们应该在DBMS 的上下文中担心,但我会提到它:fixed
数据类型,通常会导致性能影响。这取决于您在DBMS中将进行多少计算。
在MySQL中,fixed
-point data types(例如DECIMAL
)被实现为BCD strings(所以长话短说 - 再次,这里的wiki链接)。这意味着与float
相比,它会导致性能问题。但如果你不经常在DBMS中进行计算,那么这种影响甚至不会引人注意 - 我之所以提到它,因为浮点数和定点都有自己的问题。
特别是浮标不精确。是的,互联网上有很多像这样的答案,但我会重复一遍。它们不精确。关于花车,你应该不依赖精确度。并且 - 在几乎所有DBMS中都有定点数据类型。而且 - 在像你这样的情况下你应该使用它们。他们将完成同样的工作,但有了它们,你就可以确定选择的精度。
但是,您可能希望使用浮点数 - 如果您要在DBMS中进行太多计算。但是,另一方面,这是关于 - 你为什么要这样做?为什么不使用应用程序来生成这些计算(因此,避免使用定点数据类型的性能影响和浮点数的预定问题 - 因为使用具有平均计算量的定点是可以的)
答案 1 :(得分:2)
答案 2 :(得分:1)
在比较数字时,您不需要单引号。
取下单引号,然后重试。
但是,您已经注意到这可以通过ROUND(SUM(column), 2) * 1
如果单引号不起作用,请将其与此^^
的值进行比较请参阅链接:https://dev.mysql.com/doc/refman/5.0/en/problems-with-float.html