5 Stimmen

SQL Server 2005 Verlust der numerischen Genauigkeit

Beim Debuggen von SQL-Code im Finanzbereich wurde ein seltsames Problem mit der mathematischen Genauigkeit von numeric(24,8) festgestellt.

Wenn Sie die folgende Abfrage auf Ihrem MSSQL ausführen, erhalten Sie das Ergebnis des Ausdrucks A + B * C in Höhe von 0,123457

WÄHLE A, B, C, A + B * C FROM ( SELECT CAST(0.12345678 AS NUMERIC(24,8)) AS A, CAST(0 ALS NUMERIC(24,8)) AS B, CAST(500 ALS NUMERISCH(24,8)) ALS C ) T

Wir haben also 2 wichtige Symbole verloren. Beim Versuch, dies auf verschiedene Weise zu beheben, kam ich zu dem Schluss, dass die Umwandlung des Zwischenergebnisses der Multiplikation (das Null ist!) in numerisch (24,8) gut funktionieren würde.

Und endlich haben wir eine Lösung. Aber immer noch ich hace eine Frage - warum MSSQL verhält sich auf diese Weise und welche Art Konvertierungen tatsächlich in meinem Beispiel aufgetreten?

7voto

Eugene Yokota Punkte 92703

Genauso wie die Addition des Typs Float ungenau ist, kann die Multiplikation der Dezimaltypen ungenau sein (oder Ungenauigkeit verursachen), wenn Sie die Genauigkeit überschreiten. Siehe Datentyp-Konvertierung y dezimal und numerisch .

Da Sie multipliziert haben NUMERIC(24,8) y NUMERIC(24,8) Da SQL Server nur den Typ und nicht den Inhalt prüft, wird er wahrscheinlich versuchen, die möglichen 16 nicht dezimalen Stellen (24 - 8) zu speichern, wenn er nicht alle 48 Stellen der Genauigkeit (maximal 38) speichern kann. Kombiniert man zwei davon, erhält man 32 nicht-dezimale Stellen, so dass nur 6 Dezimalstellen übrig bleiben (38 - 32).

Die ursprüngliche Anfrage lautet also

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 hier gilt, dass zwischen NUMERIC(24,8) y NUMERIC(38,6) wird SQL Server versuchen, die potenziellen 32 Ziffern der Nicht-Dezimalzahlen zu speichern, also A + D reduziert auf

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

die Ihnen 0.123457 nach Rundung.

0 Stimmen

Meinten Sie NUMERIC(32,6)) ?? Wenn die Summe 38 sein muss

0 Stimmen

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

0 Stimmen

Sie sagen, dass der Server bei der Multiplikation von zwei numerischen Werten (24,8) versucht, 16 Bits einzusparen und einen Wert von (32,6) erzeugt, wie wird daraus ein Wert von 38,6? Danke

0voto

kristof Punkte 50991

Der Logik folgend, die von eed3si9n und was Sie in Ihrer Frage sagten, scheint es, dass der beste Ansatz bei der Durchführung von mathematischen Operationen darin besteht, sie in eine Funktion zu extrahieren und zusätzlich die Genauigkeit nach jeder Operation anzugeben,

In diesem Fall könnte die Funktion etwa so aussehen:

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 Stimmen

Dieser Ansatz löst möglicherweise nicht das Problem, dass SQL Server die Dezimalstellen abschneidet. Um die Dezimalstellen zu retten, kann es notwendig sein, @a und @b in double zu casten.

0 Stimmen

Danke, ich werde es im Hinterkopf behalten, wenn ich an einer Präzisionsmathematik in SQL arbeite. Bisher musste ich es noch nicht verwenden, aber es ist gut zu wissen, dass es einige Dinge zu beachten gibt.

0voto

phoenix10k Punkte 550

Trotz des Hinweises auf Genauigkeit, Maßstab und Länge (Transact-SQL) . Ich glaube, es wendet auch eine minimale "Skala" (Anzahl der Dezimalstellen) von 6 auf den resultierenden NUMERIC-Typ für die Multiplikation an, genau wie bei der Division usw.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X