Invece di intromettermi ulteriormente con la risposta di Martin, aggiungerò il resto delle mie scoperte riguardanti POWER()
qui.
Resisti ai tuoi mutandoni.
Preambolo
Innanzitutto, vi presento l'esposizione A, la documentazione MSDN perPOWER()
:
Sintassi
POWER ( float_expression , y )
argomenti
float_expression
Espressione di tipo float o di un tipo che può essere implicitamente convertita in float.
Tipi di restituzione
Come float_expression
.
Dalla lettura dell'ultima riga si può concludere che POWER()
è il tipo restituito FLOAT
, ma rileggere. float_expression
è "di tipo float o di un tipo che può essere implicitamente convertito in float". Quindi, nonostante il suo nome, float_expression
potrebbe effettivamente essere un FLOAT
, un DECIMAL
o un INT
. Poiché l'output di POWER()
è uguale a quello di float_expression
, anche questo può essere uno di quei tipi.
Quindi abbiamo una funzione scalare con tipi di ritorno che dipendono dall'input. Potrebbe essere?
osservazioni
Vi presento la mostra B, un test che dimostra che POWER()
trasmette il suo output a diversi tipi di dati a seconda del suo input .
SELECT
POWER(10, 3) AS int
, POWER(1000000000000, 3) AS numeric0 -- one trillion
, POWER(10.0, 3) AS numeric1
, POWER(10.12305, 3) AS numeric5
, POWER(1e1, 3) AS float
INTO power_test;
EXECUTE sp_help power_test;
DROP TABLE power_test;
I risultati rilevanti sono:
Column_name Type Length Prec Scale
-------------------------------------------------
int int 4 10 0
numeric0 numeric 17 38 0
numeric1 numeric 17 38 1
numeric5 numeric 17 38 5
float float 8 53 NULL
Ciò che sembra accadere è che si POWER()
proietta float_expression
nel tipo più piccolo che gli si adatta, escluso BIGINT
.
Pertanto, SELECT POWER(10.0, 38);
fallisce con un errore di overflow perché 10.0
viene lanciato su un valore NUMERIC(38, 1)
non abbastanza grande da contenere il risultato di 10 38 . Questo perché 10 38 si espande per prendere 39 cifre prima del decimale, mentre NUMERIC(38, 1)
può memorizzare 37 cifre prima del decimale più uno dopo di esso. Pertanto, il valore massimo che NUMERIC(38, 1)
può contenere è 10 37 - 0,1.
Grazie a questa comprensione, posso inventare un altro errore di overflow come segue.
SELECT POWER(1000000000, 3); -- one billion
Un miliardo (a differenza di un trilione dal primo esempio, a cui viene lanciato NUMERIC(38, 0)
) è appena abbastanza piccolo da stare in un INT
. Un miliardo elevato alla terza potenza, tuttavia, è troppo grande per INT
, quindi l'errore di overflow.
Diverse altre funzioni mostrano un comportamento simile, in cui il loro tipo di output dipende dal loro input:
- Funzioni matematiche :
POWER()
, CEILING()
, FLOOR()
, RADIANS()
, DEGREES()
, eABS()
- Funzioni di sistema e le espressioni :
NULLIF()
,ISNULL()
, COALESCE()
, IIF()
, CHOOSE()
, e CASE
le espressioni
- Operatori aritmetici : entrambi
SELECT 2 * @MAX_INT;
e SELECT @MAX_SMALLINT + @MAX_SMALLINT;
, ad esempio, provocano overflow aritmetici quando le variabili sono del tipo di dati indicato.
Conclusione
In questo caso particolare, la soluzione è usare SELECT POWER(1e1, precision)...
. Questo funzionerà per tutte le possibili precisazioni da quando 1e1
viene lanciato FLOAT
, che può contenere numeri ridicolmente grandi .
Poiché queste funzioni sono così comuni, è importante capire che i risultati potrebbero essere arrotondati o causare errori di overflow a causa del loro comportamento. Se ti aspetti o fai affidamento su un tipo di dati specifico per il tuo output, trasmetti esplicitamente l'input pertinente come necessario.
Quindi ragazzi, ora che lo sapete, potete andare avanti e prosperare.