为什么 SQL 服务器 return 数字像 0.759999 而 MySQL returns 0.76?

Why does SQL Server return numbers like 0.759999 while MySQL returns 0.76?

我有一个 SQL 服务器数据库 table,它有三列。例如,此列中的一个值可能是 0.76。这列名为 'paramvalue' 的数据被定义为 real。当我使用 pyodbc 模块命令 fetchall() 时,我得到一个类似 0.7599999904632568 而不是 0.76 的数字。我正在使用 Visual Studio 2017 和 Python 工具 Visual Studio。我也尝试过 pypyodbc 模块,但遇到了同样的问题。

table有三列,定义如下;

pconfig_id [int] IDENTITY(41,1) NOT NULL,
paramname  [nvarchar](50)       NOT NULL,
paramvalue [real]                   NULL

我的Python代码:

import pyodbc
cnxn = pyodbc.connect('DRIVER={SQL Server};SERVER=SERVERNAME;DATABASE=DBNAME;UID=USER;PWD=PASSWORD;Connect Timeout=15')
cursor = cnxn.cursor()
dict = {}
rows = cursor.execute("SELECT * FROM mytable")
for row in cursor.fetchall() :
    if not row[1] in dict.keys():
        dict[row[1]] = {}
        dict[row[1]][row[2]] = row[0]

在上面的示例中,典型行的行 [2] 的值为 0.7599999904632568 而不是预期的 0.76。

这是由于四舍五入 - Real 类型是近似值。

https://docs.microsoft.com/en-us/sql/t-sql/data-types/float-and-real-transact-sql?view=sql-server-2017

I should mention that this database was migrated from a MySQL database, in which case the type was float. When I used the MySQLdb module to fetch the data from that MySQL table it came in as 0.76 as expected.

这不是由 pyodbc 引起的问题。 MySQL 和 MSSQL 之间的区别在于浮点数 显示 .

的方式

0.76 不是可以精确表示为 32 位浮点 ("single precision") 值的值。 this site(和其他人)会告诉您,该数字最准确的表示形式是 7.599999904632568359375E-1,因此这是两个数据库存储的内容(内部表示为 0x3F428F5C)。

检索值时,MSSQL returns 写入数据库的实际值。这就是它返回 0.7599999904632568 的原因。

MySQL,另一方面,returns表示浮点值的最短字符串这将导致给定的存储值。如the documentation所述:

F -> D conversion is done with the best possible precision, returning D as the shortest string that yields F when read back in and rounded to the nearest value in native binary format as specified by IEEE.

因此,MySQL 往返 0.76,因为它恰好是对应于内部表示为 0x3F428F5C 的浮点值的最短值。这可以通过使用非常接近 0.76 但不完全相等的数字进行测试来说明:

is_mssql = (cnxn.getinfo(pyodbc.SQL_DRIVER_NAME) == 'msodbcsql17.dll')

crsr = cnxn.cursor()

test_value = '0.7599999905'
if is_mssql:
    crsr.execute("CREATE TABLE #foo (x real)")
    crsr.execute(f"INSERT INTO #foo (x) VALUES ('{test_value}')")
    result = crsr.execute("SELECT x FROM #foo").fetchval()
else:
    crsr.execute("CREATE TEMPORARY TABLE foo (x float(23))")
    crsr.execute(f"INSERT INTO foo (x) VALUES ('{test_value}')")
    result = crsr.execute("SELECT x FROM foo").fetchval()
print(f'{"MSSQL" if is_mssql else "MySQL"} returned {result}')

即使 0.7599999905 是 "actual" 值,MySQL 仍然是 returns 0.76,MSSQL 仍然是 returns 0.7599999904632568。