SQL 服务器浮动数据类型超出范围

SQL Server Float Datatype out of range

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

@variable = 120700.8000000000000000000000000000000000000000000000

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

就好像你要 运行

DECLARE @variable float = 120700.8000000000000000000000000000000000000000000000

跟踪为 运行ning 时查询成功。事件是 rpc_completed,它有持续时间、cpu、行数等...

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

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

所以我的问题是,为什么跟踪中的代码能够无误地执行,但是当我 copy/paste 将相同的代码发送到 SSMS 时它会抛出错误。如果我使用相同的代码并 trim 去掉一堆零,它就可以工作了。

我正在 运行宁 SQL Azure DB。我在兼容性 SQL2016、SQL2019 和 Prem SQL2019.

上进行了转载

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

尝试

DECLARE @variable float = 120700.8000000000000000000000000000000000000000000000E0

来源:TSQL - make a literal float value

why is the code in the trace able to execute without error, but when I copy/paste that same code to SSMS it throws an error.

当您将此查询放入 SSMS 时

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

文字 120700.8000000000000000000000000000000000000000000000 被解释为 numeric/decimal 类型。引擎尝试将其转换为 numeric/decimal 类型的值但失败了,因为数字的最大精度为 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)

中所述

why is the code in the trace able to execute without error

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

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

关于我为证明上面接受的答案所做的工作的详细信息。

我正在使用 trace 语句并使用 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 事件中获取语句。我需要对其进行解析并显式重建存储过程。