Warum "Power auswählen (10.0, 38.0)"; einen arithmetischen Überlauffehler werfen?
-
16-10-2019 - |
Frage
Ich aktualisiere mein IDENTITY
Überlaufskript zu berücksichtigen DECIMAL
und NUMERIC
IDENTITY
Säulen.
Als Teil des Schecks berechne ich die Größe des Datentyp -Bereichs für jeden IDENTITY
Säule; Ich benutze das, um zu berechnen, wie viel Prozent dieses Bereichs erschöpft waren. Zum DECIMAL
und NUMERIC
Die Größe dieses Bereichs ist 2 * 10^p - 2
wo p
ist die Präzision.
Ich habe eine Reihe von Testtabellen mit erstellt DECIMAL
und NUMERIC
IDENTITY
Spalten und versuchten, ihre Bereiche wie folgt zu berechnen:
SELECT POWER(10.0, precision)
FROM sys.columns
WHERE
is_identity = 1
AND type_is_decimal_or_numeric
;
Dies warf den folgenden Fehler:
Msg 8115, Level 16, State 6, Line 1
Arithmetic overflow error converting float to data type numeric.
Ich schränkte es auf die IDENTITY
Spalten vom Typ DECIMAL(38, 0)
(dh mit der maximalen Präzision), also habe ich dann das ausprobiert POWER()
Berechnung direkt auf diesen Wert.
Alle folgenden Fragen
SELECT POWER(10.0, 38.0);
SELECT CONVERT(FLOAT, (POWER(10.0, 38.0)));
SELECT CAST(POWER(10.0, 38.0) AS FLOAT);
führte auch zu dem gleichen Fehler.
- Warum versucht SQL Server, die Ausgabe von zu konvertieren?
POWER()
, was vom Typ istFLOAT
, zuNUMERIC
(besonders wennFLOAT
hat einen höheren Vorrang)? - Wie kann ich den Bereich von a dynamisch berechnen?
DECIMAL
oderNUMERIC
Spalte für alle möglichen Präzisionen (einschließlichp = 38
, Natürlich)?
Lösung
Von dem POWER
Dokumentation:
Syntax
POWER ( float_expression , y )
Argumente
float_expression
Ist ein Ausdruck vom Typ schweben oder von einem Typ, der implizit konvertiert werden kann schweben.y
Ist die Macht, die er erhöhen kann float_expression. y kann ein Ausdruck der exakten numerischen oder ungefähren numerischen Datentypkategorie sein, mit Ausnahme der bisschen Datentyp.Rückgabetypen
Gibt den gleichen Typ zurück wie eingereicht in float_expression. Zum Beispiel wenn a Dezimal(2,0) wird als float_expression eingereicht, das zurückgegebene Ergebnis ist Dezimal(2,0).
Der erste Eingang wird implizit auf float
im Bedarfsfall.
Die interne Berechnung wird mit Verwendung durchgeführt float
Arithmetik nach der Standardfunktion Standard C Runtime Library (CRT) pow
.
Das float
Ausgabe von pow
wird dann zurück zum Typ des linken Operanden (impliziert, um es zu sein numeric(3,1)
Wenn Sie den wörtlichen Wert 10.0 verwenden).
Mit einem expliziten float
Funktioniert in Ihrem Fall gut:
SELECT POWER(1e1, 38);
SELECT POWER(CAST(10 as float), 38.0);
Ein genaues Ergebnis für 1038 kann nicht auf einem SQL -Server gespeichert werden decimal/numeric
weil es 39 Ziffern Präzision erfordern würde (1 gefolgt von 38 Nullen). Die maximale Präzision beträgt 38.
Andere Tipps
Anstatt sich mit Martins Antwort weiter einzumischen, werde ich den Rest meiner Erkenntnisse in Bezug auf die Erkenntnisse hinzufügen POWER()
hier.
Halten Sie Ihre Schlüpfer fest.
Präambel
Erstens präsentiere ich Ihnen, Ausstellung A,, die MSDN -Dokumentation für POWER()
:
Syntax
POWER ( float_expression , y )
Argumente
float_expression
Ist ein Ausdruck des Typs des Typs oder eines Typs, der implizit in Schwimmer konvertiert werden kann.Rückgabetypen
Gleich wie
float_expression
.
Sie können aus dem Lesen dieser letzten Zeile das abschließen POWER()
Der Rückgabetyp ist FLOAT
, aber lesen Sie noch einmal. float_expression
ist "vom Typ Float oder eines Typs, der implizit in Schwimmer konvertiert werden kann". Also trotz seines Namens, float_expression
kann eigentlich ein sein FLOAT
, a DECIMAL
, oder an INT
. Seit der Ausgabe von POWER()
ist dasselbe wie das von float_expression
, Es kann auch einer dieser Typen sein.
Wir haben also eine Skalarfunktion mit Rückgabetypen, die von der Eingabe abhängen. Könnte es sein?
Beobachtungen
Ich präsentiere dir, Anlage B, ein Test, der das demonstriert, das POWER()
leitet seine Ausgabe je nach Eingabe auf verschiedene Datentypen aus. Bitte lesen Sie dieses Skript mit einem faux -jamaikanischen Akzent für maximal abgeleitete Vorteile.
SELECT
POWER(10, 3) AS int_man
, POWER(1000000000000, 3) AS numeric0_man -- one trillion
, POWER(10.0, 3) AS numeric1_man
, POWER(10.12305, 3) AS numeric5_man
, POWER(1e1, 3) AS float_man
INTO power_test_man;
EXECUTE sp_help power_test_man;
DROP TABLE power_test_man;
Die relevanten Ergebnisse sind:
Column_name Type Length Prec Scale
-------------------------------------------------
int_man int 4 10 0
numeric0_man numeric 17 38 0
numeric1_man numeric 17 38 1
numeric5_man numeric 17 38 5
float_man float 8 53 NULL
Was scheint, ist das POWER()
Abgüsse float_expression
in den kleinsten Typ, der zu ihm passt, nicht einbezogen BIGINT
.
Deswegen, SELECT POWER(10.0, 38);
versagt mit einem Überlauffehler, weil 10.0
wird gegossen NUMERIC(38, 1)
Was ist nicht groß genug, um das Ergebnis von 10 zu halten38. Das liegt daran, dass 1038 erweitert sich um 39 Ziffern vor der Dezimalzahl, während NUMERIC(38, 1)
kann 37 Ziffern vor dem Dezimal und eins danach speichern. Daher der Maximalwert NUMERIC(38, 1)
kann halten ist 1037 - 0.1.
Mit diesem Verständnis kann ich einen weiteren Überlaufversagen wie folgt zusammenfassen.
SELECT POWER(1000000000, 3); -- one billion
Eine Milliarde (im Gegen NUMERIC(38, 0)
) ist gerade klein genug, um in eine zu passen INT
. Eine Milliarde auf die dritte Macht erhoben ist jedoch zu groß für INT
, daher der Überlauffehler.
Mehrere andere Funktionen weisen ein ähnliches Verhalten auf, wobei ihr Ausgangstyp von ihrer Eingabe abhängt:
- Mathematische Funktionen:
POWER()
,CEILING()
,FLOOR()
,RADIANS()
,DEGREES()
, undABS()
- Systemfunktionen und Ausdrücke:
NULLIF()
,ISNULL()
,COALESCE()
,IIF()
,CHOOSE()
, undCASE
Ausdrücke - Rechenzeichen: Beide
SELECT 2 * @MAX_INT;
undSELECT @MAX_SMALLINT + @MAX_SMALLINT;
, Zum Beispiel führen Sie zu arithmetischen Überläufen, wenn die Variablen vom benannten Datentyp sind.
Fazit
In diesem speziellen Fall ist die Lösung zu verwenden SELECT POWER(1e1, precision)...
. Dies funktioniert für alle möglichen Präzisionen seitdem 1e1
wird gegossen FLOAT
, was halten kann Lächerlich große Zahlen.
Da diese Funktionen so alltäglich sind, ist es wichtig zu verstehen, dass Ihre Ergebnisse aufgrund ihres Verhaltens zu Überlauffehlern führen können. Wenn Sie einen bestimmten Datentyp für Ihre Ausgabe erwarten oder sich auf einen bestimmten Datentyp verlassen, geben Sie die entsprechende Eingabe nach Bedarf explizit an.
Also Kinder, jetzt wo Sie das wissen, können Sie hervorgehen und gedeihen.
Ja Mann.