Zamiast wtrącać się w odpowiedź Martina, dodam resztę moich ustaleń dotyczących POWER()
tutaj.
Trzymaj się majtek.
Preambuła
Najpierw przedstawiam wam dokumentacjęPOWER()
A, dokumentację MSDN dla :
Składnia
POWER ( float_expression , y )
Argumenty
float_expression
Jest wyrażeniem typu float lub typu, który można niejawnie przekonwertować na float.
Rodzaje zwrotów
Tak samo jak float_expression
.
Możesz wyciągnąć wniosek z przeczytania tego ostatniego wiersza, który POWER()
jest typem zwracanym FLOAT
, ale przeczytaj ponownie. float_expression
to „typu float lub typu, który można niejawnie przekonwertować na float”. Tak więc, pomimo nazwy, float_expression
może w rzeczywistości być a FLOAT
, a DECIMAL
lub an INT
. Ponieważ dane wyjściowe POWER()
są takie same, jak dane wyjściowe float_expression
, może również być jednym z tych typów.
Mamy więc funkcję skalarną z typami zwracanymi zależnymi od danych wejściowych. Czy to możliwe?
Spostrzeżenia
Przedstawiam wam wykaz B, test wykazujący, że POWER()
przekazuje on dane wyjściowe do różnych typów danych w zależności od danych wejściowych .
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;
Odpowiednie wyniki to:
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
Wydaje się, że dzieje się tak, że POWER()
rzuca float_expression
się na najmniejszy typ, który do niego pasuje, bez uwzględnienia BIGINT
.
Dlatego SELECT POWER(10.0, 38);
kończy się niepowodzeniem z błędem przepełnienia, ponieważ 10.0
zostaje rzucony, do NUMERIC(38, 1)
którego nie jest wystarczająco duży, aby pomieścić wynik 10 38 . Wynika to z faktu, że 10 38 rozwija się do 39 cyfr przed przecinkiem, natomiastNUMERIC(38, 1)
może przechowywać 37 cyfr przed przecinkiem plus jedną po nim. Dlatego maksymalna wartość, jaką NUMERIC(38, 1)
można utrzymać, to 10 37 - 0,1.
Uzbrojony w to zrozumienie, mogę wymyślić kolejną awarię przepełnienia w następujący sposób.
SELECT POWER(1000000000, 3); -- one billion
Miliard (w przeciwieństwie do jednego biliona z pierwszego przykładu, do którego trafiono NUMERIC(38, 0)
) jest wystarczająco mały, aby zmieścić się w INT
. Jednak miliard podniesiony do trzeciej potęgi jest na to za dużyINT
, dlatego wystąpił błąd przepełnienia.
Kilka innych funkcji wykazuje podobne zachowanie, przy czym ich typ wyjściowy zależy od ich danych wejściowych:
- Funkcje matematyczne :
POWER()
, CEILING()
, FLOOR()
, RADIANS()
,DEGREES()
, iABS()
- Funkcje systemowe i wyrażenia :
NULLIF()
, ISNULL()
, COALESCE()
, IIF()
, CHOOSE()
, iCASE
wyrażenia
- Operatory arytmetyczne : oba
SELECT 2 * @MAX_INT;
i SELECT @MAX_SMALLINT + @MAX_SMALLINT;
na przykład powodują przepełnienie arytmetyczne, gdy zmienne mają określony typ danych.
Wniosek
W tym konkretnym przypadku rozwiązaniem jest użycie SELECT POWER(1e1, precision)...
. Będzie to działać dla wszystkich możliwych precyzji, od kiedy 1e1
zostanie obsadzony FLOAT
, co może pomieścić absurdalnie duże liczby .
Ponieważ te funkcje są tak powszechne, ważne jest, aby zrozumieć, że wyniki mogą być zaokrąglone lub powodować błędy przepełnienia z powodu ich zachowania. Jeśli oczekujesz lub zależysz od określonego typu danych dla danych wyjściowych, jawnie oddaj odpowiednie dane wejściowe, jeśli to konieczne.
Więc dzieci, skoro już to wiesz, możesz iść naprzód i prosperować.