为什么此SQL查询失败

时间:2014-02-21 00:33:50

标签: sql sql-server

以下查询意外失败,出现算术溢出错误。

select IsNull(t2.val, 5005)
from(

SELECT 336.6 as val UNION ALL 
SELECT NULL

) as t2

"将int转换为数据类型numeric的算术溢出错误。"

奇怪的是,如果修改查询以删除NULL并将其替换为与null coalesce(5005)中相同的值,则它将无问题地运行

select IsNull(t2.val, 5005)
from(

SELECT 336.6 as val UNION ALL 
SELECT 5005

) as t2

此外,省略SELECT NULL行完全允许查询无问题地运行

select IsNull(t2.val, 5005)
from(

SELECT 336.6 as val

) as t2

如果IsNull函数中的coalesce值更改为一个小于足以在子查询中转换为十进制而不加宽的整数,则运行查询

select IsNull(t2.val, 500)
from(

SELECT 336.6 as val UNION ALL
SELECT NULL

) as t2

在SQL Server 2005和SQL Server 2008中都进行了测试。

通常将整数与小数组合是无缝的,SQL Server会将整数和小数转换为足以容纳两者的十进制类型。但由于某种原因,运行一个查询,其中从UNION和IsNull发生转换,导致转换失败。

有谁知道这是为什么?

3 个答案:

答案 0 :(得分:6)

尝试这样做

select * into t2 
from(
   SELECT 336.6 as val 
   UNION ALL 
   SELECT NULL
) as x

如果现在查看列,您会看到数字精度为4且比例为1

的数字
select * from INFORMATION_SCHEMA.COLUMNS  where TABLE_NAME='T2'

SQL根据最小的数字精度做出了这个决定,以保持336.6。现在,当你要求它将NULL转换为5005时,你要说的是,将任何NULL值转换为一个太大而不适合数字的数字,精度为4,比例为1.错误信息表示5005韩元' t适合数字(4,1)

这将起作用,因为该表现在将生成一个更大的数字字段,因为SQL需要容纳5005.使用下面的T2的新内容创建表,字段类型应该转到数字(5,1)允许5005适合。

 select IsNull(t2.val, 5005)
    from(

    SELECT 336.6 as val UNION ALL 
    SELECT 5005

    ) as t2

当你在内部查询中运行没有NULL的语句时,SQL从不评估5005,因此它不会达到需要将5005放入数字(4,1)字段的条件。

select IsNull(t2.val, 5005)
from(

SELECT 336.6 as val

) as t2

答案 1 :(得分:5)

我认为问题是当SQL Server解析联合时,它决定一个只有大到足以容纳333.6(decimal(4,1))的十进制类型。试图将5005放入其中会导致溢出。

您可以自己解决指定十进制精度的问题:

select IsNull(t2.val, 5005)
from(

SELECT CONVERT(DECIMAL(5,1), 336.6) as val UNION ALL 
SELECT NULL

) as t2

答案 2 :(得分:0)

我相信它是因为您的336.6值被推断为数据类型为NUMERIC。如果你想更具体,那么明确将它转换为DECIMAL;

    SELECT IsNull(t2.val, CAST(5005 AS DECIMAL))
    FROM (
    SELECT CAST(336.6 AS DECIMAL) AS val

    UNION ALL

    SELECT NULL
    ) AS t2