En lugar de entrometerse con la respuesta de Martin, agregaré el resto de mis hallazgos POWER()
aquí.
Agárrate a tus bragas.
Preámbulo
Primero, les presento la exhibición A, la documentación de MSDN paraPOWER()
:
Sintaxis
POWER ( float_expression , y )
Argumentos
float_expression
Es una expresión de tipo flotante o de un tipo que se puede convertir implícitamente en flotante.
Tipos de retorno
Igual que float_expression
.
Puede concluir al leer la última línea que POWER()
es el tipo de retorno FLOAT
, pero leer de nuevo. float_expression
es "de tipo flotante o de un tipo que se puede convertir implícitamente en flotante". Entonces, a pesar de su nombre, en float_expression
realidad puede ser a FLOAT
, a DECIMAL
o an INT
. Dado que la salida de POWER()
es la misma que la de float_expression
, también puede ser uno de esos tipos.
Entonces tenemos una función escalar con tipos de retorno que dependen de la entrada. ¿Podría ser?
Observaciones
Le presento la exhibición B, una prueba que demuestra que POWER()
emite su salida a diferentes tipos de datos dependiendo de su entrada .
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;
Los resultados relevantes son:
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
Lo que parece estar sucediendo es que los POWER()
moldes float_expression
en el tipo más pequeño que los ataques que, sin incluir BIGINT
.
Por lo tanto, SELECT POWER(10.0, 38);
falla con un error de desbordamiento porque se 10.0
convierte en algo NUMERIC(38, 1)
que no es lo suficientemente grande como para contener el resultado de 10 38 . Esto se debe a que 10 38 se expande para tomar 39 dígitos antes del decimal, mientras que NUMERIC(38, 1)
puede almacenar 37 dígitos antes del decimal más uno después. Por lo tanto, el valor máximo que NUMERIC(38, 1)
puede contener es 10 37 - 0.1.
Armado con este entendimiento, puedo inventar otra falla de desbordamiento de la siguiente manera.
SELECT POWER(1000000000, 3); -- one billion
Mil millones (en comparación con el billón del primer ejemplo, que se utiliza NUMERIC(38, 0)
) es lo suficientemente pequeño como para caber en un INT
. Sin embargo, mil millones recaudados a la tercera potencia son demasiado grandes INT
, de ahí el error de desbordamiento.
Varias otras funciones exhiben un comportamiento similar, donde su tipo de salida depende de su entrada:
- Funciones matemáticas :
POWER()
, CEILING()
, FLOOR()
, RADIANS()
, DEGREES()
, yABS()
- Funciones del sistema y expresiones :
NULLIF()
, ISNULL()
, COALESCE()
, IIF()
, CHOOSE()
, y CASE
expresiones
- Operadores aritméticos : Ambos
SELECT 2 * @MAX_INT;
y SELECT @MAX_SMALLINT + @MAX_SMALLINT;
, por ejemplo, producen desbordamientos aritméticos cuando las variables son del tipo de datos con nombre.
Conclusión
En este caso particular, la solución es usar SELECT POWER(1e1, precision)...
. Esto funcionará para todas las precisiones posibles desde que 1e1
se emite FLOAT
, que puede contener números ridículamente grandes .
Dado que estas funciones son tan comunes, es importante comprender que sus resultados pueden ser redondeados o pueden causar errores de desbordamiento debido a su comportamiento. Si espera o confía en un tipo de datos específico para su salida, emita explícitamente la entrada relevante según sea necesario.
Entonces, niños, ahora que saben esto, pueden salir y prosperar.