简体   繁体   English

SQL Server ROUND()不适用于以1结尾的FLOAT

[英]SQL Server ROUND() not working for FLOAT ending in 1

I changed my example to use FLOAT's ... too many people were getting hung up on the whole NVARCHAR thing. 我改变了我的例子以使用FLOAT ......太多人被挂在整个NVARCHAR上。 We are not storing numbers in the database as NVARCHAR. 我们不会将数据存储在数据库中作为NVARCHAR。 I was just using NVARCHAR as an example. 我只是以NVARCHAR为例。 I get the same results with FLOAT. 我用FLOAT得到了相同的结果。

We're having issues with the SQL Server ROUND() for some FLOAT's 对于某些FLOAT,我们遇到了SQL Server ROUND()的问题

DECLARE @EXCHANGE_RATE FLOAT
    SET @EXCHANGE_RATE = 1.327810000000000000000
    SELECT ROUND(@EXCHANGE_RATE,6,1)
    SET @EXCHANGE_RATE = 1.327820000000000000000
    SELECT ROUND(@EXCHANGE_RATE,6,1)

First one returns : 1.327809 Second one returns: 1.32782 第一个返回:1.327809第二个返回:1.32782

You would think the first one would return 1.32781, and not 1.327809. 你会认为第一个会返回1.32781,而不是1.327809。

Is this a feature or bug in the ROUND? 这是ROUND中的功能还是错误? Any easy way around it? 有什么简单的方法吗?

Thanks! 谢谢!

Based on Mat's idea of casting them as DECIMAL, this works ... it's ugly, but works. 基于Mat的将它们作为DECIMAL进行渲染的想法,这是有效的......它很丑陋,但有效。 The reason I use 10, is I looked in our database, and that seems to be the longest number we store. 我使用10的原因是我查看了我们的数据库,这似乎是我们存储的最长数字。 Also I need to convert it back to FLOAT because they don't want to see any trailing 0's 此外,我需要将其转换回FLOAT,因为他们不希望看到任何尾随0

DECLARE @EXCHANGE_RATE FLOAT
    SET @EXCHANGE_RATE = 1.327810000000000000000
    SELECT CAST(ROUND(CAST(@EXCHANGE_RATE AS DECIMAL(28,10)),6,1) AS FLOAT)

Try this query. 试试这个查询。

SELECT
  ROUND('1.3278100',6,0)                     AS x0,
  ROUND('1.3278200',6,0)                     AS y0,
  ROUND('1.3278100',6,1)                     AS x1,
  ROUND('1.3278200',6,1)                     AS y1,

  ROUND(CAST( '1.3278100' AS FLOAT), 6, 0)   AS a0,
  ROUND(CAST( '1.3278200' AS FLOAT), 6, 0)   AS b0,
  ROUND(CAST( '1.3278100' AS FLOAT), 6, 1)   AS a1,
  ROUND(CAST( '1.3278200' AS FLOAT), 6, 1)   AS b1,

  ROUND(CAST( '1.3278100' AS DECIMAL(9,8)), 6, 0)   AS i0,
  ROUND(CAST( '1.3278200' AS DECIMAL(9,8)), 6, 0)   AS j0,
  ROUND(CAST( '1.3278100' AS DECIMAL(9,8)), 6, 1)   AS i1,
  ROUND(CAST( '1.3278200' AS DECIMAL(9,8)), 6, 1)   AS j1
;

http://sqlfiddle.com/#!6/d41d8/15607 http://sqlfiddle.com/#!6/d41d8/15607

What this indicates to me is that ROUND() is implicitly casting your VARCHAR values to FLOAT before truncating them. 这对我来说是指ROUND()在截断它们之前隐式地将你的VARCHAR值转换为FLOAT

And as FLOATs can't accurately represent 1.327810, you're actually truncating 1.3278099999999 (or something similar). 由于FLOAT无法准确表示1.327810,因此您实际上截断了1.3278099999999(或类似的东西)。

So, in short, explicitly cast them to DECIMAL before you truncate. 因此,简而言之,在截断之前将它们明确地转换为DECIMAL。 Or simply don't store numeric data as strings... 或者只是不将数字数据存储为字符串......

I'll leave the below here for the moment, it is true, but it is not the reason for the op's issue. 我现在暂时离开这里,这是事实,但这不是op问题的原因。
The correct answer is the one provided by MatBailie, -the nVarChar string is being converted to a float, and then the truncation operation is reducing it to the next lower value... 正确的答案是MatBailie提供的答案 - nVarChar字符串被转换为浮点数,然后截断操作将其减少到下一个较低的值...

From MSDN for Round function 从MSDN for Round功能

function 功能
Is the type of operation to perform. 是要执行的操作类型。 function must be tinyint, smallint, or int. function必须是tinyint,smallint或int。 When function is omitted or has a value of 0 (default), numeric_expression is rounded. 省略function或者值为0(默认值)时,numeric_expression将四舍五入。 *When a value other than 0 is specified, numeric_expression is truncated.* *当指定0以外的值时,将截断numeric_expression。*

try this, it shows the difference: 试试这个,它显示了差异:

DECLARE @EXCHANGE_RATE NVARCHAR(200)
SET @EXCHANGE_RATE = '1.3278100'
SELECT ROUND(@EXCHANGE_RATE,6,0) Rounded,
       ROUND(@EXCHANGE_RATE,6,1) Truncated

SET @EXCHANGE_RATE = '1.327810000001'
SELECT ROUND(@EXCHANGE_RATE,6,0) Rounded,
       ROUND(@EXCHANGE_RATE,6,1) Truncated

the output type is determined by the input... In this case, the input is '1.3278100', so the value is cast to a numeric datatype, with a precision based on the number of significant digits in the string ('1.3278100' has 5 significant digits) so the output type is determined to be numeric(6,5) or something like that... this causes the unexpected truncation. 输出类型由输入确定...在这种情况下,输入为'1.3278100',因此该值将转换为数字数据类型,其精度基于字符串中的有效位数('1.3278100'具有5位有效数字)因此输出类型被确定为数字(6,5)或类似的东西......这会导致意外截断。 This has bitten me before. 这之前我一直在咬我。

Use ROUND(@var,6) instead of ROUND(@var,6,1) . 使用ROUND(@var,6)代替ROUND(@var,6,1) There is a 3rd optional parameter in the ROUND() function and it looks like you don't need it here. ROUND()函数中有第3个可选参数,看起来你在这里不需要它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM