Замість того, щоб більше втручатися у відповідь Мартіна, я додам решту моїх висновків щодо POWER()
цього.
Тримайтеся за ваші взутті.
Преамбула
По-перше, я представляю вам виставку A, документацію MSDN щодоPOWER()
:
Синтаксис
POWER ( float_expression , y )
Аргументи
float_expression
Це вираз float типу або типу, який можна неявно перетворити на float.
Типи повернення
Те саме, що float_expression
.
Ви можете зробити висновок, прочитавши той останній рядок, який POWER()
є типом повернення FLOAT
, але прочитати його ще раз. float_expression
є "float типу або типу, який можна неявно перетворити на float". Отже, незважаючи на свою назву, float_expression
насправді може бути а FLOAT
, а DECIMAL
чи а 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
може бути переданий , що може вміти смішно велику кількість .
Оскільки ці функції настільки звичні, важливо розуміти, що ваші результати можуть бути округленими або можуть спричинити помилки переповнення через їх поведінку. Якщо ви очікуєте або покладаєтесь на певний тип даних для свого результату, явно подайте відповідний вхід, якщо це необхідно.
Тож діти, тепер, коли ви це знаєте, ви можете піти і процвітати.