提问人:JoeLeBaron 提问时间:7/2/2020 更新时间:7/3/2020 访问量:2559
SQL Server Float 数据类型超出范围
SQL Server Float Datatype out of range
问:
我有一个查询,我通过扩展事件会话捕获,其浮点数据类型如下所示:
@variable = 120700.8000000000000000000000000000000000000000000000
如果我尝试在 SSMS 中运行相同的查询,则会出现错误:数字“120700.80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
就像你要跑步一样
DECLARE @variable float = 120700.8000000000000000000000000000000000000000000000
跟踪运行时查询成功。事件是rpc_completed的,它有持续时间、cpu、行数等......
不确定这是否相关,但有问题的查询是执行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
尝试
DECLARE @variable float = 120700.8000000000000000000000000000000000000000000000E0
为什么跟踪中的代码能够无错误地执行,但是当我 将相同的代码复制/粘贴到 SSMS,它会引发错误。
将此查询放入 SSMS 时
exec sp_executeSQL N'SELECT
col1,
col2
FROM table
WHERE col3 > @variable', N'@variable float',
@variable = 120700.8000000000000000000000000000000000000000000000
文本被解释为数字/十进制类型。引擎尝试将其转换为数字/十进制类型的值,但失败,因为数字的最大精度为 38 位。120700.8000000000000000000000000000000000000000000000
如果将此查询放在 SSMS 中,它应该可以正常工作
exec sp_executeSQL N'SELECT
col1,
col2
FROM table
WHERE col3 > @variable', N'@variable float',
@variable = 120700.8000000000000000000000000000000000000000000000E0
我在最后添加了。E0
若要使文字成为文字,我们需要使用科学记数法,如常量 (Transact-SQL) 中所述float
为什么跟踪中的代码能够执行而不会出错
我不能肯定地说,但我怀疑您在跟踪中看到的代码与应用程序发送到 SQL Server 的代码并不完全相同。它可以以这样一种方式发送,即参数类型和值实际上是 ,而不是具有所有这些零的文本字符串。float
我认为,应用程序可能会进行RPC调用,将具有适当类型的适当参数传递给函数调用。因此,当应用程序成功调用时,从未发生过从文本字符串到或类型的转换。numeric
float
评论
关于我为证明上述公认的答案所做的工作的详细信息。
我正在使用 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事件中获取声明。我需要解析它并显式重建存储过程。
评论
120700.8000000000000000000000000000000000000000000000
120700.8000000000000000000000000000000000000000000000E0