Вместо того, чтобы больше вмешиваться в ответ Мартина, я добавлю остальные мои выводы, касающиеся POWER()
здесь.
Держись за свои трусики.
преамбула
Сначала я представляю вам экспонат А, документацию MSDN дляPOWER()
:
Синтаксис
POWER ( float_expression , y )
аргументы
float_expression
Выражение типа float или типа, который можно неявно преобразовать в float.
Типы возврата
Такой же как float_expression
.
Из этой последней строки вы можете сделать вывод, что POWER()
тип возвращаемого значения - FLOAT
но прочитайте еще раз. float_expression
имеет тип типа float или типа, который может быть неявно преобразован в тип float. Таким образом, несмотря на название, на float_expression
самом деле это может быть a FLOAT
, a DECIMAL
или an INT
. Так как выходные данные POWER()
такие же, как и у float_expression
, они также могут быть одним из этих типов.
Итак, у нас есть скалярная функция с типами возвращаемых данных, которые зависят от входных данных. Может ли это быть?
наблюдения
Я представляю вам экспонат B, тест, демонстрирующий, что POWER()
вывод его данных выполняется в зависимости от типа входных данных .
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;
Соответствующие результаты:
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
То , что кажется, происходит то , что POWER()
забросы float_expression
в наименьшему типу , который соответствует его, не включая BIGINT
.
Таким образом, происходит SELECT POWER(10.0, 38);
сбой с ошибкой переполнения, поскольку 10.0
происходит приведение к типу, NUMERIC(38, 1)
который недостаточно велик, чтобы содержать результат 10 38 . Это связано с тем, что 10 38 расширяется до 39 цифр перед десятичной запятой, тогда как NUMERIC(38, 1)
может хранить 37 цифр до десятичной запятой и одну после нее. Следовательно, максимальное значение NUMERIC(38, 1)
может быть 10 37 - 0,1.
Вооружившись этим пониманием, я могу придумать еще одну ошибку переполнения следующим образом.
SELECT POWER(1000000000, 3); -- one billion
Один миллиард (в отличие от одного триллиона из первого примера, который приведен NUMERIC(38, 0)
) - достаточно мал, чтобы уместиться в INT
. Однако миллиард, возведенный в третью степень, слишком велик INT
, поэтому возникает ошибка переполнения.
Несколько других функций демонстрируют аналогичное поведение, где их тип вывода зависит от их ввода:
- Математические функции :
POWER()
, CEILING()
, FLOOR()
, RADIANS()
, DEGREES()
, иABS()
- Системные функции и выражение :
NULLIF()
, ISNULL()
, COALESCE()
, IIF()
, CHOOSE()
, и CASE
выражение
- Арифметические операторы :
SELECT 2 * @MAX_INT;
и то и другое SELECT @MAX_SMALLINT + @MAX_SMALLINT;
, например, приводят к арифметическим переполнениям, когда переменные имеют именованный тип данных.
Вывод
В данном конкретном случае решение заключается в использовании SELECT POWER(1e1, precision)...
. Это сработает для всех возможных значений точности с момента 1e1
приведения к нему FLOAT
, который может содержать смехотворно большие числа .
Поскольку эти функции настолько распространены, важно понимать, что ваши результаты могут быть округлены или могут вызвать ошибки переполнения из-за их поведения. Если вы ожидаете или полагаетесь на конкретный тип данных для своего вывода, явно приведите соответствующий ввод при необходимости.
Итак, дети, теперь, когда вы это знаете, вы можете идти дальше и процветать.