web-dev-qa-db-ja.com

算術オーバーフローエラー

このコードを実行すると:

select 99999 * 9999

結果= 999890001

このコードを実行すると:

select 9999923 * 99999999

結果:

メッセージ8115、レベル16、状態2、行1
式をデータ型intに変換する算術オーバーフローエラー。

そして、私が次のコードを実行すると:

select 922337299987987689745893 * 999999994564

結果= 922337294974162127011191918541325652

特定の範囲内でこの算術オーバーフローエラーが発生するのはなぜですか?

5
John Stone

SQL Serverがリテラルのタイプを導出するために使用するルールは複雑で、下位互換性のために最近維持されているいくつかの奇妙な動作があります。たとえば、派生型は、単純なパラメーター化が適用されているかどうかによって異なります。他にも(文書化されていない)考慮事項があります。

これらの警告が解決されると、直面する状況はより単純なものの1つになります。型なしリテラルは、そのデータ型に収まる場合はintegerとして型指定されます。結果のデータ型は *(乗算)(Transact-SQL) で指定されているとおりです。

優先順位の高い引数のデータ型を返します。
詳細については、 Data Type Precedence(Transact-SQL) を参照してください。

2つのデータ型はどちらもinteger(明らかに同じ優先順位)であるため、結果もintegerとして型指定されます。結果が収まらない場合、(設定によっては)エラーがスローされる場合があります。

リテラルの1つがCASTまたはCONVERTを(たとえば)bigintintegerより優先順位が高い)として明示的に入力された場合、結果の型はbigintとなり、エラーは発生しません。

質問の2つのより大きな定数は、それぞれnumeric(24,0)およびnumeric(12,0)として入力されます。それらを乗算した結果は、 精度、スケール、および長さ(Transact-SQL)に示されている_e1 * e2_の規則に従って、numeric(37,0)として型指定されます

結果の精度:p1 + p2 + 1 = 24 + 12 + 1 = 37
結果スケール:s1 + s2 = 0 + 0 = 
 
結果タイプ: 数値(37,0)
10
Paul White 9

Microsoft documentation では、

10進数ではない式の精度と位取りは、式のデータ型に対して定義された精度と位取りです。

入力はintと見なされるため、結果は2 147 483 647未満を意味するintであると想定されます。それより大きい場合、実際にエラーが発生します。

入力の1つをbigintなどの別のデータ型としてキャストしても、失敗しません。

select 9999923 * cast(99999999 as bigint)
-- 999992290000077
6
irimias

これは、各リテラル番号が存在すると解釈されるデフォルトのデータ型によるものです。

最初の2つのクエリの数値には、INTのデータ型が割り当てられています。 3番目のクエリの多数には、NUMERIC(24, 0)のデータ型が割り当てられています(NUMERICDECIMALは同義語です)。

これを確認するには、 SQL_VARIANT_PROPERTY 関数を使用して、リテラルのresultingデータ型の詳細(**注:SQL_VARIANT_PROPERTYは、SQL Serverによって選択された初期タイプをすべてのケースで返すとは限りません):

_SELECT SQL_VARIANT_PROPERTY(99999, 'BaseType') AS [TypeFor99999],
       SQL_VARIANT_PROPERTY(9999, 'BaseType') AS [TypeFor9999],
       SQL_VARIANT_PROPERTY(9999923, 'BaseType') AS [TypeFor9999923],
       SQL_VARIANT_PROPERTY(99999999, 'BaseType') AS [TypeFor99999999];
_

戻り値:

_int   int   int   int
_

その後:

_SELECT SQL_VARIANT_PROPERTY(922337299987987689745893, 'BaseType') AS [Type],
       SQL_VARIANT_PROPERTY(922337299987987689745893, 'Precision') AS [Precision],
       SQL_VARIANT_PROPERTY(922337299987987689745893, 'Scale') AS [Scale];
_

戻り値:

_numeric 24  0
_

そして完全な表現はあなたに与える:

_SELECT SQL_VARIANT_PROPERTY(922337299987987689745893 * 999999994564, 'BaseType') AS [Type],
       SQL_VARIANT_PROPERTY(922337299987987689745893 * 999999994564, 'Precision') AS [Precision],
       SQL_VARIANT_PROPERTY(922337299987987689745893 * 999999994564, 'Scale') AS [Scale];
_

戻り値:

_numeric 37  0
_

エラーが発生したクエリの場合は、CONVERT(BIGINT, 9999923)を介してBIGINTに変換します。例えば:

_SELECT CONVERT(BIGINT, 9999923) * 99999999
_

戻り値:

_999992290000077
_
4
Solomon Rutzky