SQL Server 2005 numerische Genauigkeit Verlust
-
02-07-2019 - |
Frage
Debuggen einiger finanzbezogenen SQL-Code ein seltsames Problem mit numeric (24,8) Mathematik Präzision gefunden.
Ausführen der folgenden Abfrage auf Ihrem MSSQL Sie A + B * C Ausdruck Ergebnis erhalten würde 0,123457
seinA SELECT, B, C, A + B * C VON ( SELECT CAST (0.12345678 als numerische (24,8)) als A, CAST (0 AS ZIFFERN (24,8)) als B, CAST (500 AS ZIFFERN (24,8)) als C ) T
So haben wir zwei bedeutende Symbole verloren. Der Versuch, dies erhalten auf verschiedene Weise festgelegt bekam ich, dass die Umwandlung des Zwischenmultiplikationsergebnisses (die Null!) In numerischen (24,8) würde gut funktionieren.
Und schließlich eine Lösung. Aber noch hace ich eine Frage - warum MSSQL auf diese Weise verhält und welche Typkonvertierungen in meiner Probe tatsächlich aufgetreten
?Lösung
Wie Zugabe des Schwimmers Typ ist ungenau, Multiplikation der Dezimaltypen können ungenau sein (oder Ungenauigkeit verursachen), wenn Sie die Genauigkeit nicht überschreiten. Siehe Datentypkonvertierung und decimal und numeric .
Da Sie NUMERIC(24,8)
und NUMERIC(24,8)
multipliziert und SQL Server wird nur die Art überprüfen nicht der Inhalt, es wird wahrscheinlich versuchen, die möglichen 16 nicht-Dezimalstellen zu speichern (24-8), wenn sie nicht alle 48 Ziffern speichern kann Genauigkeit (max 38). Kombinieren Sie zwei von ihnen, erhalten Sie 32 Nicht-Dezimalstellen, die Sie mit nur 6 Dezimalstellen Blätter (38-32).
Damit wird die ursprüngliche Abfrage
SELECT A, B, C, A + B * C
FROM ( SELECT CAST(0.12345678 AS NUMERIC(24,8)) AS A,
CAST(0 AS NUMERIC(24,8)) AS B,
CAST(500 AS NUMERIC(24,8)) AS C ) T
reduziert auf
SELECT A, B, C, A + D
FROM ( SELECT CAST(0.12345678 AS NUMERIC(24,8)) AS A,
CAST(0 AS NUMERIC(24,8)) AS B,
CAST(500 AS NUMERIC(24,8)) AS C,
CAST(0 AS NUMERIC(38,6)) AS D ) T
Auch zwischen NUMERIC(24,8)
und NUMERIC(38,6)
, wird SQL Server versuchen, die möglichen 32 Stellen von Nicht-Dezimalstellen zu speichern, so A + D
zu reduzieren
SELECT CAST(0.12345678 AS NUMERIC(38,6))
das gibt Sie 0.123457
nach dem Runden.
Andere Tipps
der Logik folgend wies darauf hin, von eed3si9n und was Sie gesagt haben in Ihrer Frage scheint es, dass der beste Ansatz, wenn Mathematik Operationen ist, um sie in eine Funktion zu extrahieren und zusätzlich angeben Präzision nach jeder Operation,
tunEs diesem Fall ist die Funktion etwas aussehen könnte:
create function dbo.myMath(@a as numeric(24,8), @b as numeric(24,8), @c as numeric(24,8))
returns numeric(24,8)
as
begin
declare @d as numeric(24,8)
set @d = @b* @c
return @a + @d
end
Trotz allem, was er sagt, auf Precision, Mensur und Länge (Transact-SQL) . Ich glaube, es ist auch ein Minimum ‚Skala‘ (Anzahl der Dezimalstellen) von 6 zur resultierenden NUMERIC-Typ für die Multiplikation der Anwendung das gleiche wie es funktioniert für die Division etc.