在SQL Server数据库表的十进制(18,6)列中插入2147483648或更大值时,转换为int时出现算术溢出



我在SQL Server 2012中遇到了这个问题,但它在SQL Server 2017中也很明显。

我的数据库表,称为MyTable,包含一个decimal(18,6)new_balance,它不可为null。该表还包含两个整数列,它们是主键的一部分。没有其他整数字段。

存储过程具有参数@new_balance,该参数也被定义为decimal(18,6)。还有id(@id(和seq_num(@seq_num(的参数,它们都被定义为int

该程序按照以下行插入表格:

INSERT INTO MyTable (id, seq_num, new_balance)
VALUES (@id, @seq_num, @new_balance);

@new_balance设置为2147483647.999999或更低时,插入按预期进行
@new_balance设置为大于或等于2147483648的数字时,例如2147483648.1,该过程将失败,并导致算术溢出将表达式转换为int错误。我很感激int列的最大值是2147483647。

使用以下插入也是这种情况:

INSERT INTO MyTable (id, seq_num, new_balance)
SELECT @id, @seq_num, @new_balance;

考虑到参数和表列都被定义为decimal(18,6),我很难理解为什么在插入时会转换为int(尤其是在第二条语句中,我不希望有任何隐式转换(。

作为INSERT语句的一部分,我还尝试将@new_balance显式转换为decimal(18,6)

INSERT INTO MyTable (id, seq_num, new_balance)
SELECT @id, @seq_num, CAST(@new_balance AS decimal(18,6));

这也没有奏效。

奇怪的是,如果我在查询中指定一个具有相同定义的表变量并执行类似的插入,它会很好地工作:

DECLARE @MyTable TABLE (id int, seq_num int, new_balance decimal(18,6));
INSERT INTO @MyTable (id, seq_num, new_balance)
SELECT @id, @seq_num, @new_balance;

我在过程中尝试过这种方法,即首先将记录插入@MyTable,然后尝试插入MyTable,如下所示:

DECLARE @MyTable TABLE (id int, seq_num int, new_balance decimal(18,6));
INSERT INTO @MyTable (id, seq_num, new_balance) SELECT @id, @seq_num, @new_balance;
INSERT INTO MyTable (id, seq_num, new_balance) SELECT id, seq_num, new_balance FROM @MyTable;

这也没用。

为了完整起见,我还尝试创建一个值为零的记录,然后更新现有的记录——同样,这是不成功的,因此INSERT和update都会出现这个问题:

INSERT INTO MyTable (id, seq_num, new_balance) SELECT @id, @seq_num, 0.00;

这很好,但下一步会出现与上面报告的错误相同的错误:

UPDATE MyTable SET new_balance = @new_balance WHERE id = @id AND seq_num = @seq_num;

要确认,表上没有INSTEAD OF INSERT触发器或AFTER UPDATE触发器-没有任何类型的触发器。

数据库上未启用更改跟踪,并且此特定字段没有约束-实际表中的其他十进制(18,6(字段有默认约束。

数据库中也没有添加任何视图。

我在这个论坛上的第一个问题——希望有人自己也经历过,也许知道如何解决它,尽管我找不到类似性质的问题。我被难住了。

由于能够在过程之外直接插入到表中,我查看了一些下游事件并确定了问题:

插入记录后,系统会更新父表中关联记录的状态。此父表上有一个AFTER UPDATE,它将此状态更改标识为需要审核,并运行一个辅助过程来创建审核历史记录。作为捕获的一部分,系统使用标量值函数将MyTable中的新旧值转换为用户友好的格式。作为其中的一部分,该值被拆分为两部分以创建必要的格式,并且整个数字部分被转换为int。通过将此转换更改为bigint,问题自行解决。

因此,最初问题的前提是错误的——这个问题有好几层。

感谢那些做出贡献的人。

最新更新