【问题标题】:Select 1024*1024*1024*1024 fails选择 1024*1024*1024*1024 失败
【发布时间】:2016-07-05 07:40:18
【问题描述】:

有人能解释一下为什么SELECT的整数乘法会失败吗?

SELECT 1024*1024*1024*1024 -- ERROR

是不是乘法结果大于INT数据类型阈值?

DECLARE @VAL AS BIGINT
SET @VAL = 1024 -- OK
SET @VAL = 1024*1024 -- OK
SET @VAL = 1024*1024*1024 -- OK
SET @VAL = 1024*1024*1024*1024 -- ERROR
SET @VAL = 1099511627776 -- OK - 1024*1024*1024*1024=1099511627776
SET @VAL = CAST((1024*1024*1024*1024) AS BIGINT) -- ERROR

错误信息

将表达式转换为数据类型 int 时出现算术溢出错误。

int, bigint, smallint, and tinyint (Transact-SQL)

注意

当您使用 +、-、*、/ 或 % 算术运算符将 int、smallint、tinyint 或 bigint 常量值隐式或显式转换为 float、real、decimal 或 numeric 数据类型时,规则SQL Server 在计算表达式结果的数据类型和精度时应用的内容取决于查询是否自动参数化。

因此,查询中的相似表达式有时会产生不同的结果。当查询未自动参数化时,在转换为指定的数据类型之前,首先将常量值转换为精度刚好足以容纳常量值的数值。例如,常量值 1 转换为数值 (1, 0),常量值 250 转换为数值 (3, 0)。

当查询被自动参数化时,常量值总是在转换为最终数据类型之前转换为数字 (10, 0)。当涉及 / 运算符时,不仅结果类型的精度在相似查询之间会有所不同,而且结果值也会有所不同。例如,包含表达式 SELECT CAST (1.0 / 7 AS float) 的自动参数化查询的结果值将不同于未自动参数化的同一查询的结果值,因为自动参​​数化查询的结果将被截断以适应转化为数字 (10, 0) 数据类型。

【问题讨论】:

  • 是的,这就是算术溢出,内存不足来存储结果。
  • 错误消息似乎很明显 - “将表达式转换为数据类型 int 的算术溢出错误。”推测一个int是32位的,1024^4 == (2^10)^4 == 2^40 超出了32位Integer (2^32)的范围
  • SELECT CAST(1024 AS BIGINT) * 1024 * 1024 *1024
  • 试试select SQL_VARIANT_PROPERTY(CONVERT(sql_variant,1099511627776),'BaseType') 看看为什么你的select 1099511627776 有效,但不是你想象的那样。
  • 谢谢 Damien,但为什么 select SQL_VARIANT_PROPERTY(CONVERT(sql_variant,1024*1024*1024*1024.0),'BaseType') 返回数字而不是浮点数?

标签: sql-server


【解决方案1】:

因为 1024 是一个整数。 SQL-Server 采用第一种数据类型来生成算术函数。

从左到右评估术语。

如果你写 1099511627776 它是一个数值。

将第一个值转换为 bigint(或数字),然后就可以了:

select cast(1 as bigint)*1024*1024*1024*1024

【讨论】:

  • “这是一个 bigint”——不,不是。这是numeric。请参阅问题评论中发布的示例。
  • 是的,你是对的 - 它是数字(13,0) - 我更正了我的答案。
【解决方案2】:

在这种情况下,SQL 将默认使用 INT 类型来完成操作。这解释了为什么如果结果值溢出 INT 的最大容量 (2,147,483,647),您会收到错误消息。

一种解决方法可能是将您在操作中使用的数字存储在 BIGINT 变量中:

DECLARE @NUMBER AS BIGINT = 1024
DECLARE @VAL AS BIGINT
SET @VAL = @NUMBER
SET @VAL = @NUMBER*@NUMBER
SET @VAL = @NUMBER*@NUMBER*@NUMBER
SET @VAL = @NUMBER*@NUMBER*@NUMBER*@NUMBER
SET @VAL = 1099511627776
SET @VAL = CAST((@NUMBER*@NUMBER*@NUMBER*@NUMBER) AS BIGINT)

【讨论】:

    【解决方案3】:

    刚刚找到一个查询,经过更多谷歌搜索后不会抛出错误;如果我将其中一个值转换为十进制/数字,即 1024.0

    见TSQL Arithmetic overflow using BIGINT

    SELECT 1024*1024*1024*1024.0 -- OK
    DECLARE @VAL AS BIGINT
    SET @VAL = 1024 -- OK
    SET @VAL = 1024*1024 -- OK
    SET @VAL = 1024*1024*1024 -- OK
    SET @VAL = 1024*1024*1024*1024.0 -- OK
    SET @VAL = 1099511627776 -- OK
    
    select SQL_VARIANT_PROPERTY(CONVERT(sql_variant,1024.0),'BaseType')  -- numeric
    select SQL_VARIANT_PROPERTY(CONVERT(sql_variant,1024*1024*1024*1024.0),'BaseType')   -- numeric
    

    【讨论】:

    • FLOAT 不是精确的数据类型,小心使用它!
    • 这是否意味着会引入精度误差?我如何了解更多信息?
    • 是的,它可能会产生精度错误。阅读文档中关于浮点数和实数数据类型的文章。在 SO 上搜索 SQL Server 精度错误或使用您喜欢的搜索引擎查找一些示例。这是来自 SO 的问题之一:stackoverflow.com/questions/4199371/…
    猜你喜欢
    • 2014-09-20
    • 2013-12-28
    • 2014-08-31
    • 2021-03-24
    • 2020-05-06
    • 2012-08-15
    • 2012-09-18
    • 2015-02-16
    • 1970-01-01
    相关资源
    最近更新 更多