提问人:sveti petar 提问时间:4/28/2014 最后编辑:O. Jonessveti petar 更新时间:5/18/2014 访问量:10030
MySQL“大于”条件有时会返回值相等的行
MySQL "greater than" condition sometimes returns row with equal value
问:
我在基本的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'
它回来了!所以就好像它认为表中的 973.88 大于 973.88,但它并没有犯与 995.12 相同的错误。无论我是从 PHP 脚本还是在 phpMyAdmin 中运行查询,都会发生这种情况。4
有什么想法吗?
答:
比较数字时不需要单引号。
去掉单引号,然后重试。
但是,这已被指出是您可以解决的问题ROUND(SUM(column), 2) * 1
如果单引号不起作用,请将其与此^^的值进行比较
请参阅链接:https://dev.mysql.com/doc/refman/5.0/en/problems-with-float.html
@Hituptony是正确的。试试这个:
SELECT * FROM (`users`) WHERE `rating` > 973.88
决定和后果
这就是你得到的后果,因为你决定使用浮点数据类型。浮点数不精确。这意味着:是的,你可以得到 a>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)
哎呀!
幕后花絮
为什么?要理解为什么会这样,您应该了解浮点数据类型的表示方式。长话短说。但是 - 我将简要概述一下。
以下是它的表示方式:其中:
s
是标志b
是基础。它的意思与基数相同e
是指数。
这意味着我们可以用不同的方式表示一个数字 - 这取决于我们将选择哪个基数。最常见的是 。但并非所有实数都可以用这个基数精确表示,即使在十进制基数中它们看起来“不错”。著名的例子是 - 无法精确表示 - 因此它被近似存储。同样,你可以在这里看到很长的故事 - 但我只想指出,不可能用基数 2 精确地表示它。b=2
0.1
b=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)
多田!奇迹发生了。您的号码现在以固定精度存储,因此,此类比较失败。
使用 float
然后,可能会有一些用例,当你被浮点数困住时(但是,在DBMS的情况下,我甚至很难记住一个这样的用例 - 如果不是大量计算的情况,这可能会导致性能影响,请参阅下面的描述)。然后仍然有办法让它工作。您应该决定适合您的精度。也就是说:从哪一点开始,您将把数字视为平等。
您只存储了两个有效数字,因此我认为 的精度绰绰有余。然后,您的查询将如下所示: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 | +------+---------+
哪个更好?
要意识到这一点,您需要再次查看掩体。我已经简要概述了什么是数据类型以及为什么它不精确。但是,数据类型也有其弱点。在DBMS的上下文中,我们可能不应该担心这一点,但我要提到的是:数据类型通常会导致性能影响。这将取决于您将在 DBMS 中进行多少计算。float
fixed
fixed
在MySQL中,定
点数据类型(例如)被实现为BCD字符串(所以长话短说 - 再次,这里是wiki链接)。这意味着与它相比会导致性能问题。但是,如果您不打算经常在 DBMS 中进行计算,那么这种影响甚至不会很明显 - 我之所以提到它,是因为浮点和定点这两种类型都有自己的问题。DECIMAL
float
结论
DBMS和所有其他计算机一样,并不完美。它只是使用一些内部的东西来完成工作。这意味着:在某些情况下,你必须意识到内部的东西是如何运作的,才能理解为什么你会得到一些奇怪的结果。
特别是,浮点数并不精确。是的,互联网上有大量这样的答案,但我会再说一遍。它们并不精确。当涉及到浮点数时,你不应该依赖精度。而且 - 在几乎所有的 DBMS 中,都有定点数据类型。而且 - 在像您这样的情况下,您应该使用它们。它们将执行相同的工作,但有了它们,您将确定所选的精度。
但是,如果要在 DBMS 中进行过多计算,则可能需要使用浮点数。但是,另一方面,这是关于 - 你为什么要这样做?为什么不使用应用程序来生成这些计算(因此,避免使用定点数据类型和浮点数的前提问题对性能的影响 - 因为使用定点和平均计算量是可以的)
评论
FLOAT
DECIMAL
FLOAT
DOUBLE
DATE
评论
rating
float(8,2)