SQL Server中WHERE子句中的浮点数问题

8

我正在尝试查询一个数据库,需要获取一个客户列表,其中他们的体重等于60.5。问题是60.5是一个实数,我以前从未在where子句中使用过实数进行数据库查询。

我尝试了以下代码:

SELECT Name FROM Customers WHERE Weight=60.5
SELECT Name FROM Customers WHERE Weight=cast(60.5 as real)
SELECT Name FROM Customers WHERE Weight=cast(60.5 as decimal)
SELECT Name FROM Customers WHERE Weight=convert(real,'60.5')
SELECT Name FROM Customers WHERE Weight=convert(decimal,'60.5')

这些查询返回的值为0,但在顾客表中有10行重量为60.5。


Weight 的确切类型是什么? - Dmytro Shevchenko
列“Weight”的确切类型为实数。 - flofreelance
如果您运行 SELECT Name FROM Customers WHERE Weight BETWEEN 60 and 61,您会得到什么?使用实数或浮点数的原因非常少。除非这是航天飞机的应用程序,否则实数绝对不适合表示人的体重。请改用 decimal(19,2)。 - Nick.McDermaid
为什么?我不知道那不是我的说法。航天飞机部分只是一个讽刺的评论。 - Nick.McDermaid
2个回答

19

你的问题在于浮点数本质上是不精确的。与字面值60.5进行比较可能会出现问题,这一点你已经注意到了。

一个典型的解决方案是测量2个值之间的差异,如果小于某个预定义的epsilon,则认为它们相等:

SELECT Name FROM Customers WHERE ABS(Weight-60.5) < 0.001

为了获得更好的性能,你应该实际使用:

SELECT Name FROM Customers WHERE Weight BETWEEN 64.999 AND 65.001

1
可以使用范围谓词来使其可搜索。 - Martin Smith
@MartinSmith - 同意! - Amit

2
如果您需要进行等值比较,您应该将列的类型更改为DECIMAL。十进制数被精确地存储和比较,而实数和浮点数则是近似值。
@Amit的答案可以工作,但与我的方法相比效率会相当低下。 ABS(Weight-60.5)<0.001 无法使用索引搜索。但如果您将列转换为DECIMAL,那么Weight=60.5将表现良好并使用索引搜索。

我认为那是一条有用的普遍建议,但不一定适用于这里(或其他地方)。 - Amit
我支持 +1 阵营,但必须强调并表示我不喜欢“竞争风格”。 - Amit
我已经给这个点踩了,因为它并没有解决所提出的问题(如何在实数列上执行WHERE操作),而是建议对表进行非平凡更改... - steenbergh
嘿@Amit,我实际上已经点赞了你的答案,并且我同意它回答了问题。我添加了我的答案作为一种通常更好的方法(至少在我看来),这是OP没有想到的。它可能更适合他的需求。我并不是要与你竞争,但我仍然需要一种方式来指出两种方法之间的差异。如果你能建议更好的措辞方式,我会很感激。谢谢! - Dmytro Shevchenko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接