2

SqlDecimalsを使用すると、予期しない結果が発生します。結局、2つのSqlDecimalsを分割するとき、問題をスケーリングするために要約するようです。

c#のサンプルコードは次のようになります:

[Microsoft.SqlServer.Server.SqlFunction]
[return: SqlFacet(Precision = 38, Scale = 8)]
public static SqlDecimal fn_divide([SqlFacet(Precision = 38, Scale = 8)]SqlDecimal x, [SqlFacet(Precision = 38, Scale = 8)]SqlDecimal y)
{
    var r = SqlDecimal.Divide(@x, @y);

    return r;
}

SQLテストコードは次のようになります。

DECLARE @x numeric(38, 8),
        @y numeric(38, 8)

SELECT @x = Replicate('1', 28) + '.12345678',
       @y = '0.25896314'

SELECT via = 'TSQL', x = @x, y = @y, r = Convert(numeric(38, 8),  @x / @y)
SELECT via = 'SQLCLR', x = @x, y = @y, r = dbo.fn_divide(@x, @y)

2番目の選択では、次のエラーが返されます。

A .NET Framework error occurred during execution of user-defined routine or aggregate "fn_divide": `
System.OverflowException: Arithmetic Overflow.
System.OverflowException: 
   at System.Data.SqlTypes.SqlDecimal.MultByULong(UInt32 uiMultiplier)
   at System.Data.SqlTypes.SqlDecimal.AdjustScale(Int32 digits, Boolean fRound)
   at System.Data.SqlTypes.SqlDecimal.op_Division(SqlDecimal x, SqlDecimal y)
   at System.Data.SqlTypes.SqlDecimal.Divide(SqlDecimal x, SqlDecimal y)
  at UserDefinedFunctions.fn_divide(SqlDecimal x, SqlDecimal y)

Webを検索すると、SqlDecimalをDecimalに変換するときの丸め誤差に関連する問題がたくさん見つかりましたが、私の場合は、それを正確に避けたかったので、最初から最後まですべてSqlDecimalです。同様に、結果がSQLでネイティブに実装された方法と同じになることを「期待」しますが、残念ながら。オーバーフローしない場合でも、「border-cases」で異なる結果が得られます。

誰かがこれを修正する方法、または少なくともそれを回避する方法について何かヒントがありますか?SqlDecimalは内部で(.Net)Decimalsを使用しているため、3バイトの情報を詰め込むことができませんか?!?!?

PS:numeric(p、s)のどの組み合わせが関数に渡されるかを予測することはできませんが、38,8は「許容可能」です。私は、元のUDFのより高速なSQLCLRバージョンを作成することを望んでいました(これは、btw =を除算するだけではありません)。確かに、それは大丈夫ですが、同じ範囲の数値で機能するはずです。

4

0 に答える 0