将 2,147,483,648 或更大值插入 SQL 服务器数据库 table 中的 decimal(18,6) 列时,算术溢出转换为 int

Arithmetic overflow converting to int when inserting 2,147,483,648 or greater into decimal(18,6) column in SQL Server database table

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

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

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

该程序按照以下行执行插入到 table 中:

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;

鉴于参数和 table 列都定义为 decimal(18,6),我很难理解为什么在插入过程中会转换为 int(尤其是第二个语句,其中我不希望有任何隐式转换)。

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

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

这也没有用。

奇怪的是,如果我在查询中指定一个具有相同定义的 table 变量并执行类似的插入,它就可以正常工作:

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 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;

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

数据库未启用更改跟踪,并且此特定字段没有约束 - 实际 table.[=37 中的其他 decimal(18,6) 字段有默认约束=]

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

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

在能够直接插入过程之外的 table 之后,我查看了一些下游事件并确定了问题所在:

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

因此,原问题的前提是错误的 - 这个问题有好几层。

感谢贡献者。