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 调用,将具有适当类型的适当参数传递给函数调用。因此,当应用程序成功调用时,从未将文本字符串转换为 numeric
或 float
类型。
【讨论】:
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类型转换超出范围的报错