SQL Server 浮点数据类型超出范围

Posted

技术标签:

【中文标题】SQL Server 浮点数据类型超出范围【英文标题】:SQL Server Float Datatype out of range 【发布时间】:2020-10-22 04:37:15 【问题描述】:

我有一个通过扩展事件会话捕获的查询,其浮点数据类型如下所示:

@variable = 120700.8000000000000000000000000000000000000000000000

如果我尝试在 SSMS 中运行相同的查询,我会收到错误消息: 数字“120700.8000000000000000000000000000000000000000000000”超出了数字表示的范围(最大精度为 38)。

就像你要跑步一样

DECLARE @variable float = 120700.8000000000000000000000000000000000000000000000

跟踪运行时查询成功。 Event 是 rpc_completed,它有一个持续时间、cpu、rowcount 等...

不确定这是否相关,但有问题的查询是 exec sp_executeSQL。跟踪捕获的完整查询如下所示:

exec sp_executeSQL N'SELECT
    col1,
    col2
FROM table
WHERE col3 > @variable', N'@variable float', 
@variable = 120700.8000000000000000000000000000000000000000000000

所以我的问题是,为什么跟踪中的代码能够无错误地执行,但是当我将相同的代码复制/粘贴到 SSMS 时,它会引发错误。如果我采用相同的代码并去掉一堆零,它就可以工作。

我在 SQL Azure DB 上运行。我已经在兼容性 SQL2016、SQL2019 和 Prem SQL2019 上进行了转载。

【问题讨论】:

文字 120700.8000000000000000000000000000000000000000000000 首先隐式转换为十进制,因此出现错误。试试120700.8000000000000000000000000000000000000000000000E0(最后注E0)来源:***.com/questions/3024306/… @VladimirBaranov - 完成;忍不住点赞:) 【参考方案1】:

为什么跟踪中的代码能够正常执行,但是当我 将相同的代码复制/粘贴到 SSMS 会引发错误。

当您将此查询放入 SSMS 时

exec sp_executeSQL N'SELECT
    col1,
    col2
FROM table
WHERE col3 > @variable', N'@variable float', 
@variable = 120700.8000000000000000000000000000000000000000000000

文字120700.8000000000000000000000000000000000000000000000 被解释为数字/十进制类型。引擎尝试将其转换为数字/十进制类型的值并失败,因为数字的最大精度为 38 位。

如果你把这个查询放在 SSMS 中,它应该可以工作

exec sp_executeSQL N'SELECT
    col1,
    col2
FROM table
WHERE col3 > @variable', N'@variable float', 
@variable = 120700.8000000000000000000000000000000000000000000000E0

我在末尾添加了E0

要使float 成为文字,我们需要使用科学记数法,如Constants (Transact-SQL) 中所述


为什么跟踪中的代码能够正常执行

我不能肯定地说,但我怀疑您在跟踪中看到的代码与应用程序发送到 SQL Server 的代码并不完全相同。它可能以这样一种方式发送,即参数类型和值实际上是float,而不是所有这些零的文本字符串。

我认为,应用程序可能会进行 RPC 调用,将具有适当类型的适当参数传递给函数调用。因此,当应用程序成功调用时,从未将文本字符串转换为 numericfloat 类型。

【讨论】:

RE "RPC 调用以正确的类型传递正确的参数" - 我也这么认为。它看起来像一个参数化查询。唯一让我感到困惑的是数字中的尾随 0。这只是格式上的怪异吗? @Alex,这很可能是跟踪呈现/显示/格式化其数据的奇怪方式。我没有很多扩展活动的经验。 这让我走上了正轨。我只是将整个命令放入 Command.Text 属性中,将语句从跟踪中取出并在 C# 中执行。我需要作为存储过程执行并显式声明参数。我将在下面添加一个答案,说明我的意思。【参考方案2】:

字符串文字 120700.8000000000000000000000000000000000000000000000 首先被隐式转换为十进制,因此出现错误。

试试

DECLARE @variable float = 120700.8000000000000000000000000000000000000000000000E0

来源:TSQL - make a literal float value

【讨论】:

【参考方案3】:

详细说明我为证明上述接受的答案所做的工作。

我正在使用跟踪语句并使用 C# 在另一个数据库上重放它(这将引发超出范围错误):

cmd.CommandType = System.Data.CommandType.Text;
cmd.CommandText = "exec sp_executesql @stmt=N'SELECT @f',
    @params=N'@f float',@f=120700.800000000002910383045673370361328125";
cmd.ExecuteNonQuery();

我需要做的是提取这些部分并使用如下参数构建一个存储过程:

cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.CommandText = "sp_executesql";

SqlParameter p1 = new SqlParameter();
p1.DbType = System.Data.DbType.String;
p1.ParameterName = "@stmt";
p1.Value = "SELECT @f";

SqlParameter p2 = new SqlParameter();
p2.DbType = System.Data.DbType.String;
p2.ParameterName = "@params";
p2.Value = "@f float";

SqlParameter p3 = new SqlParameter();
p3.DbType = System.Data.DbType.Double;
p3.Value = 120700.8000000000000000000000000000000000000000000000;
p3.ParameterName = "@f";

cmd.Parameters.Add(p1);
cmd.Parameters.Add(p2);
cmd.Parameters.Add(p3);

cmd.ExecuteNonQuery();

当我运行它时,它在跟踪中显示为:

exec sp_executesql @stmt=N'SELECT @f',@params=N'@f float',@f=120700.800000000002910383045673370361328125

所以问题是我不能只从 rpc_completed 事件中获取语句。我需要对其进行解析并显式重构存储过程。

【讨论】:

仅供参考:SQL Server Profiler 允许您重播事件:docs.microsoft.com/en-us/sql/tools/sql-server-profiler/… 很遗憾,Profiler 不适用于 Azure SQL DB。

以上是关于SQL Server 浮点数据类型超出范围的主要内容,如果未能解决你的问题,请参考以下文章

将 char 数据类型转换为 datetime 数据类型导致 SQL Server 2005 中的 datetime 值超出范围

[SQL Server]从 varchar 数据类型到 datetime 数据类型的转换产生一个超出范围的值。

sql server中单引号拼接字符串(书写错误会出现错误"浮点值 XXXX 超出了计算机表示范围(8 个字节)。“XX”附近有语法错误。")

SQL Server datetime类型转换超出范围的报错

将 varchar 数据类型转换为 datetime 数据类型导致值超出范围的问题

错误 sql:将 varchar 数据类型转换为 datetime 数据类型导致值超出范围