当 BCD 映射规则处于活动状态时,在 INSERT 查询中转换参数值会导致算术溢出

Casting a parameter value in INSERT query gives arithmetic overflow when BCD mapping rules are active

在 MSSQL 数据库中考虑这个 table:

CREATE TABLE dbo.TESTPAR
(
  ID INTEGER NOT NULL,
  YR VARCHAR(50) NULL
)

我有一个 TFDQuery 命令文本:

insert into TESTPAR
(ID,YR)
values(:ID,cast(:YR as varchar(4)))

这有两个 ftInteger ptInput 参数

执行
procedure TFrmCastAsVarchar.BtnTestInsertClick(Sender: TObject);
begin
   Inc(FLastID);
   FDQuery2.Params[0].AsInteger := FLastID;
   FDQuery2.Params[1].AsInteger := 2018;
   try
      FDQuery2.ExecSQL;
   except
      on E:Exception do ShowMessage(E.Message);
   end;
end;

当 dtBCD 和 dtFmtBCD 字段的映射处于活动状态时出现错误 EMSSQLNativeException Arithmetic overflow converting numeric to data type varchar

procedure TDM.SetBCDMapRules;
// For (Fmt)BCD data types. Called from SetOracleMapRules/SetMSSQLMapRules
begin
   with FDConnection.FormatOptions.MapRules.Add do
   begin      // Convert numeric data types with scale=0 and precision<=10 to a 32-bit integer
      PrecMax := 10;
      PrecMin :=  0;
      ScaleMax := 0;
      ScaleMin := 0;
      SourceDataType := dtBCD;
      TargetDataType := dtInt32;
   end;
   with FDConnection.FormatOptions.MapRules.Add do
   begin      // Do the same for those that might return as dtFmtBCD instead of dtBCD
      PrecMax := 10;
      PrecMin :=  0;
      ScaleMax := 0;
      ScaleMin := 0;
      SourceDataType := dtFmtBCD;
      TargetDataType := dtInt32;
   end;
   with FDConnection.FormatOptions.MapRules.Add do
   begin      // Convert numeric data types with scale=0 and precision>10 to a 64-bit integer
      PrecMin := 11;
      ScaleMax := 0;
      ScaleMin := 0;
      SourceDataType := dtBCD;
      TargetDataType := dtInt64;
   end;
   with FDConnection.FormatOptions.MapRules.Add do
   begin      // Idem dtFmtBCD
      PrecMin := 11;
      ScaleMax := 0;
      ScaleMin := 0;
      SourceDataType := dtFmtBCD;
      TargetDataType := dtInt64;
   end;
   with FDConnection.FormatOptions.MapRules.Add do
   begin      // All other dtBCD types (notably scale <> 0) should return as float
      SourceDataType := dtBCD;
      TargetDataType := dtDouble;
   end;
   with FDConnection.FormatOptions.MapRules.Add do
   begin      // Idem dtFmtBCD
      SourceDataType := dtFmtBCD;
      TargetDataType := dtDouble;
   end;
end;

(如何)我可以更改 SQL 来解决这个问题?
或者,我的映射规则中有什么奇怪的东西可以修复吗?我很惊讶这有什么影响。

当然,您的映射有问题(我们一直在这个 ). For parameters, it is transformation of target into source. The Data Type Mapping 主题中说:

In case of a command parameter, the rule defines a transformation of a target data type, specified by an application, into a source data type, supported by a driver.

因此,在这种情况下,您已指示 FireDAC 将 32 位整数转换为十进制数,当到达 DBMS 时,它不会只有 4 个字符长。如果你想解决这个问题,那么(按可靠性排序):

  • 在 table
  • 中使用正确的数据类型
  • 一般停止使用映射规则
  • 使用正确的参数数据类型并按实际情况传递值(以字符串形式,而非整数形式)
  • 将参数值转换为整数,例如CAST(CAST(:YR AS INTEGER) AS VARCHAR(4))