5

Debugging einige Finanz-SQL-Code gefunden ein seltsames Problem mit numerischen (24,8) Mathematik Genauigkeit.SQL Server 2005 numerische Genauigkeit Verlust

die folgende Abfrage auf Ihrem MSSQL Laufen Sie A + B * C Ausdruck Ergebnis erhalten würde 0,123457

SELECT A, B, C, A + B * C VON ( SELECT CAST sein (0.12345678 als numerisches (24,8)) als A, CAST (0 AS ZIFFERN (24,8)) als B, CAST (500 AS ZIFFERN (24,8)) als C ) T

So Wir haben 2 signifikante Symbole verloren. Versucht man, dies auf verschiedene Arten zu fixieren, bekam ich die Umwandlung des Zwischenergebnisses (welches Null ist!) Zu numerisch (24,8).

Und schließlich eine Lösung haben. Aber ich habe noch eine Frage - warum MSSQL auf diese Weise verhält und welche Typumwandlungen tatsächlich in meiner Probe vorkamen?

Antwort

7

Genau wie die Addition des Float-Typs ungenau ist, kann die Multiplikation der Dezimaltypen ungenau sein (oder Ungenauigkeit verursachen), wenn Sie die Genauigkeit überschreiten. Siehe Data Type Conversion und decimal and numeric.

Da Sie multipliziert NUMERIC(24,8) und NUMERIC(24,8), und SQL Server wird nur den Typ nicht den Inhalt überprüfen, wird es wahrscheinlich versuchen, die potenziellen 16 Nicht-Dezimalstellen (24 - 8) zu speichern, wenn es nicht alle 48 Ziffern speichern kann Präzision (max ist 38). Kombinieren Sie zwei von ihnen, Sie erhalten 32 Nicht-Dezimalziffern, die Sie mit nur 6 Dezimalziffern (38 bis 32) verlassen.

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 sich 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), SQL Server versuchen, die möglichen 32 Stellen von Nicht-Dezimalstellen zu speichern, so A + D reduziert sich auf

SELECT CAST(0.12345678 AS NUMERIC(38,6)) 

welche gi Ves Sie 0.123457 nach dem Runden.

+0

meinst du NUMERIC (32,6)) ?? Wenn die Summe muss 38 – Edmondo1984

+0

@ Edmondo1984 Bitte lesen Sie die Links und verstehen, was beide Zahlen bedeuten. –

+0

Sie sagen, dass der Server versuchen wird, 16 Bits zu speichern und eine (32,6) zu erzeugen, wenn man zwei Zahlen (24,8) multipliziert, wie wird es ein 38,6?Danke – Edmondo1984

0

wies die Logik folgend durch eed3si9n und was die Sie in Ihrer Frage scheint es, dass der beste Ansatz, wenn Mathematik Operationen extrahieren sie in eine Funktion und zusätzlich angeben Präzision nach jeder Operation, diese

Es tut 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 
+0

Dieser Ansatz löst möglicherweise nicht das Problem, dass SQL Server die Dezimalteile abschneidet. Um die Dezimalteile zu speichern, müssen Sie möglicherweise @a und @b in Double konvertieren. –

+0

Danke, ich werde es im Hinterkopf behalten, wenn ich an etwas präzisem Mathe in SQL arbeite, Bisher muss ich es nicht verwenden, aber es ist gut, dass es jetzt einige Probleme gibt, die zu berücksichtigen sind – kristof