SQL Server 2012を実行しています
SELECT
0.15 * 30 / 360,
0.15 / 360 * 30
結果:
0.012500,
0.012480
これは私を混乱させるほどです。
DECLARE @N INT = 360
DECLARE @I DECIMAL(38,26) = 0.15 * 30 / 360
DECLARE @C DECIMAL(38,26) = 1000000
SELECT @C * @I * POWER(1 + @I, @N) / ( POWER(1 + @I, @N) - 1 )
SELECT @C * (@I * POWER(1 + @I, @N) / ( POWER(1 + @I, @N) - 1 ) )
最初の選択では正しい結果が得られます:12644.44022 2番目の選択では結果が切り捨てられます:12644.00000
式から生じる精度とスケールの決定は ラットのネスト であり、特に10進数(またはfloat!)とintを混合する場合、誰もがすべてのシナリオの正確な規則を理解していないと思います。 gbnによるこの回答 を参照してください。
もちろん、式を調整して、より詳細な明示的な変換を行うことで、必要なものを取得できます。これはおそらくやり過ぎですが:
SELECT
CONVERT(DECIMAL(15,6), CONVERT(DECIMAL(15,6), 0.15)
* CONVERT(DECIMAL(15,6), 30)
/ CONVERT(DECIMAL(15,6), 360)),
CONVERT(DECIMAL(15,6), CONVERT(DECIMAL(15,6), 0.15)
/ CONVERT(DECIMAL(15,6), 360)
* CONVERT(DECIMAL(15,6), 30));
どちらの結果も、浮動小数点演算が壊れていたり、精度やスケールが大幅に間違っていたりするために誤って丸められることはありません。
0.012500 0.012500
Aaron Bertrandが述べたように、式は予測が非常に困難です。
そこに行くなら、次のスニペットを使用して洞察を得ることができます。
DECLARE @number SQL_VARIANT
SELECT @number = 0.15 / 360
SELECT @number
SELECT
SQL_VARIANT_PROPERTY(@number, 'BaseType') BaseType,
SQL_VARIANT_PROPERTY(@number, 'MaxLength') MaxLength,
SQL_VARIANT_PROPERTY(@number, 'Precision') Precision
これが結果です:
------------
0.000416
(1 row(s) affected)
BaseType MaxLength Precision
------------ ------------ ----------
numeric 5 6
(1 row(s) affected)
この質問に優れた回答が既に追加されているにもかかわらず、SQL Serverでのデータ型の変換には、明示的に定義された優先順位があります。
演算子が異なるデータ型の2つの式を組み合わせる場合、データ型の優先順位の規則は、優先順位の低いデータ型を優先順位の高いデータ型に変換することを指定します。変換がサポートされている暗黙の変換でない場合は、エラーが返されます。両方のオペランド式が同じデータ型の場合、演算の結果はそのデータ型になります。
SQL Serverは、データ型に次の優先順位を使用します。
_user-defined data types (highest)
sql_variant
xml
datetimeoffset
datetime2
datetime
smalldatetime
date
time
float
real
decimal
money
smallmoney
bigint
int
smallint
tinyint
bit
ntext
text
image
timestamp
uniqueidentifier
nvarchar (including nvarchar(max) )
nchar
varchar (including varchar(max) )
char
varbinary (including varbinary(max) )
binary (lowest)
_
したがって、たとえば、_SELECT 0.5 * 1
_(10進数にintを乗算)の場合、10進数値に変換される結果が得られます。これは、decimal
がhigherであるためですint
データ型よりも優先されます。
詳細は http://msdn.Microsoft.com/en-us/library/ms190309.aspx を参照してください。
すべてのことを言っても、実際にはすべての入力が10進数であるため、SELECT @C * (@I * POWER(1 + @I, @N) / (POWER(1 + @I, @N) - 1 ));
shouldはおそらく10進数の値を返します。興味深いことに、SELECT
を次のように変更することにより、正しい結果を強制できます。
_DECLARE @N INT = 360;
DECLARE @I DECIMAL(38,26) = 0.15 * 30 / 360;
DECLARE @C DECIMAL(38,26) = 1000000;
SELECT @C * @I * POWER(1 + @I, @N) / (POWER(1 + @I, @N) - 1);
SELECT @C * (@I * POWER(1 + @I, @N) / (POWER(1E0 + @I, @N) - 1));
_
これは次を返します:
howは説明に困惑していますが、明確にそれはです。私のguessは_1E0
_関数の_POWER(
_(明示的な浮動小数点)であり、SQL ServerはPOWER
の出力タイプに異なる選択を強制します関数。 ドキュメントの状態POWER()
への最初の入力は浮動小数点数、または暗黙的に指定できる数値であるため、私の推測が正しい場合、POWER
関数のバグの可能性を示していますfloatに変換されます。
SELECT .. INTO
構文 ?これは、指定されたSELECT
リストに適切なデータ型のみを使用してテーブルを即座に作成するため、このような状況を解体するのに役立ちます。
計算を構成ステップに分割し、SQL Serverの優先順位ルールを適用しながら適用して、定義がどのように変化するかを確認できます。最初の例は次のようになります。
use tempdb;
SELECT
0.15 as a,
0.15 * 30 as b,
0.15 * 30 / 360 as c
into #Step1;
select * from #Step1;
select
c.name,
t.name,
c.precision,
c.scale
from sys.columns as c
inner join sys.types as t
on t.system_type_id = c.system_type_id
where object_id = object_id('#Step1');
drop table #Step1;
これは出力です:
name name precision scale
a numeric 2 2
b numeric 5 2
c numeric 9 6