所以我在SQL Server中遇到了一个带有舍入的奇怪问题。
这是我的例子:
declare @amount float = 178.69999999
select
@amount as [amount],
round(@amount, 6) as [round],
round(round(@amount, 6), 2, 1) as [trim_1],
floor(round(@amount, 6) * power(10.0, 2)) / power(10.0, 2) as [trim_2]
这是我得到的结果:
+--------------+-------+--------+--------+
| amount | round | trim_1 | trim_2 |
+--------------+-------+--------+--------+
| 178.69999999 | 178.7 | 178.69 | 178.7 |
+--------------+-------+--------+--------+
这里的一般想法是我试图舍入6位小数,然后修剪/ floor / truncate 2位小数。这意味着我期待178.7
的结果,但我得到178.69
的trim_1
的结果(trim_2
是另一种方法,意味着产生相同的结果)。
据我所知,我正在使用round
函数,正如SQL Server documentation所述:
句法
ROUND ( numeric_expression , length [ ,function ] )
功能
是要执行的操作类型。 function必须是tinyint,smallint或int。省略function或者值为0(默认值)时,numeric_expression将四舍五入。如果指定了0以外的值,则会截断numeric_expression。
所以我希望trim_1
能够匹配trim_2
。
这是踢球者:如果我将round
的结果作为常量传递,而不是作为变量,它按预期工作:
select round(178.7, 2, 1) -- Yields 178.7
我的猜测是SQL Server正在用浮点做一些奇怪的事情,或者我已经设法错过了一些东西。对于它的价值,我正在使用SQL Server 2014,所以也许这就是我的问题。
我想用尽可能少的代码得到trim_1
的结果,这样我的最终结果看起来更干净。
使用decimal
而不是float
。
取自Float and Real (Transact-SQL)
浮点数据是近似值;因此,并非数据类型范围中的所有值都可以准确表示。
在代码中用float
替换decimal
会得到所需的结果:
declare @amount decimal(18, 10) = 178.69999999
select
@amount as [amount],
round(@amount, 6) as [round],
round(round(@amount, 6), 2, 1) as [trim_1],
floor(round(@amount, 6) * power(10.0, 2)) / power(10.0, 2) as [trim_2]
结果:
╔════════════════╦════════════════╦════════════════╦════════════╗ ║ amount ║ round ║ trim_1 ║ trim_2 ║ ╠════════════════╬════════════════╬════════════════╬════════════╣ ║ 178.6999999900 ║ 178.7000000000 ║ 178.7000000000 ║ 178.700000 ║ ╚════════════════╩════════════════╩════════════════╩════════════╝