このコードを実行すると:
select 99999 * 9999
結果= 999890001
このコードを実行すると:
select 9999923 * 99999999
結果:
メッセージ8115、レベル16、状態2、行1
式をデータ型intに変換する算術オーバーフローエラー。
そして、私が次のコードを実行すると:
select 922337299987987689745893 * 999999994564
結果= 922337294974162127011191918541325652
特定の範囲内でこの算術オーバーフローエラーが発生するのはなぜですか?
SQL Serverがリテラルのタイプを導出するために使用するルールは複雑で、下位互換性のために最近維持されているいくつかの奇妙な動作があります。たとえば、派生型は、単純なパラメーター化が適用されているかどうかによって異なります。他にも(文書化されていない)考慮事項があります。
これらの警告が解決されると、直面する状況はより単純なものの1つになります。型なしリテラルは、そのデータ型に収まる場合はinteger
として型指定されます。結果のデータ型は *(乗算)(Transact-SQL) で指定されているとおりです。
優先順位の高い引数のデータ型を返します。
詳細については、 Data Type Precedence(Transact-SQL) を参照してください。
2つのデータ型はどちらもinteger
(明らかに同じ優先順位)であるため、結果もinteger
として型指定されます。結果が収まらない場合、(設定によっては)エラーがスローされる場合があります。
リテラルの1つがCAST
またはCONVERT
を(たとえば)bigint
(integer
より優先順位が高い)として明示的に入力された場合、結果の型は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)
Microsoft documentation では、
10進数ではない式の精度と位取りは、式のデータ型に対して定義された精度と位取りです。
入力はintと見なされるため、結果は2 147 483 647未満を意味するintであると想定されます。それより大きい場合、実際にエラーが発生します。
入力の1つをbigintなどの別のデータ型としてキャストしても、失敗しません。
select 9999923 * cast(99999999 as bigint)
-- 999992290000077
これは、各リテラル番号が存在すると解釈されるデフォルトのデータ型によるものです。
最初の2つのクエリの数値には、INT
のデータ型が割り当てられています。 3番目のクエリの多数には、NUMERIC(24, 0)
のデータ型が割り当てられています(NUMERIC
とDECIMAL
は同義語です)。
これを確認するには、 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
_