【问题标题】:Arithmetic overflow error (numeric to numeric) with MERGE: SQL Server bug?MERGE 的算术溢出错误(数字到数字):SQL Server 错误?
【发布时间】:2012-06-07 14:51:24
【问题描述】:

我有一个目标表TargetTable,它有一个DECIMAL(20, 7) 列。我还有一个源表SourceTable,它有一个DECIMAL(20, 7) 列,但是这个表中的值无论如何都是整数。

当我尝试通过 MERGE 语句将数据从 SourceTable 插入到 TargetTable 时,出现标准错误。

将数字转换为数字数据类型时出现算术溢出错误。

我真的不明白为什么会发生这种情况,因为这两种数据类型是相同的。

不过,奇怪的是:当我在 TargetTable 上使用 SELECT INTO 创建测试表 TestTable,然后将合并目标更改为 TestTable,则 upsert 完成。我也不明白为什么会这样,因为TargetTableTestTable 大部分是相同的。

以前有没有人遇到过这种情况,这是一个错误,还是我遗漏了 SQL Server 的一些模糊细微差别?


示例代码

失败:

SET NUMERIC_ROUNDABORT Off
GO

MERGE
    TargetTable Target
USING
    (
        SELECT
            cast(forecast as DECIMAL(20, 7)) forecast
          ,[SegmentID]
          ,[Country]
          ,[Environment]
          ,[YearColumn]
          ,[ForecastYear]
          ,[Criterion]
        FROM
            SourceTable
    ) Source
    ON
    (
        Target.SegmentID = Source.SegmentID
        AND Target.Country = Source.Country
        AND Target.Environment = Source.Environment
        AND Target.YearColumn = Source.YearColumn
        AND Target.ForecastYear = Source.ForecastYear
        AND Target.Criterion = Source.Criterion
    )
WHEN NOT MATCHED BY TARGET AND Source.Forecast <> 0 AND Source.Forecast IS NOT NULL THEN
    INSERT (SegmentID, Country, Environment, YearColumn, Forecast, ForecastYear, Criterion)
    VALUES (Source.SegmentID, Source.Country, Source.Environment, Source.YearColumn, Source.Forecast, Source.ForecastYear, Source.Criterion)
WHEN MATCHED AND (Source.Forecast = 0 OR Source.Forecast IS NULL) THEN
    DELETE
WHEN MATCHED AND Source.Forecast <> Target.Forecast THEN
    UPDATE SET Target.Forecast = Source.Forecast;

成功:

SELECT
    *
INTO
    TestTable
FROM
    TargetTable
GO

SET NUMERIC_ROUNDABORT Off
GO

MERGE
    TestTable Target
USING
    (
        SELECT
            cast(forecast as DECIMAL(20, 7)) forecast
          ,[SegmentID]
          ,[Country]
          ,[Environment]
          ,[YearColumn]
          ,[ForecastYear]
          ,[Criterion]
        FROM
            SourceTable
    ) Source
    ON
    (
        Target.SegmentID = Source.SegmentID
        AND Target.Country = Source.Country
        AND Target.Environment = Source.Environment
        AND Target.YearColumn = Source.YearColumn
        AND Target.ForecastYear = Source.ForecastYear
        AND Target.Criterion = Source.Criterion
    )
WHEN NOT MATCHED BY TARGET AND Source.Forecast <> 0 AND Source.Forecast IS NOT NULL THEN
    INSERT (SegmentID, Country, Environment, YearColumn, Forecast, ForecastYear, Criterion)
    VALUES (Source.SegmentID, Source.Country, Source.Environment, Source.YearColumn, Source.Forecast, Source.ForecastYear, Source.Criterion)
WHEN MATCHED AND (Source.Forecast = 0 OR Source.Forecast IS NULL) THEN
    DELETE
WHEN MATCHED AND Source.Forecast <> Target.Forecast THEN
    UPDATE SET Target.Forecast = Source.Forecast;

【问题讨论】:

  • 另外,如果这听起来比 SO 更适合 dba.stackexchange.com,请权衡一下。
  • 请发布您正在使用的查询,以便我们为您提供帮助
  • @Lamak:我认为没有必要发布代码,因为这似乎在原则上比在细节上更不一致,但我会发布代码。
  • 您为什么不尝试使用 SET NUMERIC_ROUNDABORT Off 并查看将哪些结果插入到目标表中。这可能会让您了解是否有任何数据丢失
  • TargetTable 上是否有可能导致此错误的触发器?

标签: sql sql-server sql-server-2008


【解决方案1】:

您的代码似乎完全没有错误。此外,当您使用与原始表相同的结构和数据创建另一个表作为目标时,它可以正常工作,这表明错误不存在。最可能的原因是您的原始表上有一个触发器正在执行失败的查询,这就是您看到的错误。

【讨论】:

  • 那么,理论上,我不必毕竟必须发布代码? :) 但再次感谢您的分享。
  • 实际上,如果不查看您的代码,我永远无法确定没有错误,并且可能的罪魁祸首是触发器
【解决方案2】:

发生这种类型的错误是因为您可以对特定表使用触发器,但是该表上下文或数据库中执行了一些更改,因此它显示错误这种类型的错误,所以请禁用触发器并执行任务

【讨论】:

  • 您的答案将通过一段演示您所说内容的示例代码得到改进。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多