Au lieu de me mêler davantage de la réponse de Martin, je vais ajouter le reste de mes conclusions concernant POWER()
ici.
Accrochez-vous à votre culotte.
Préambule
Tout d'abord, je vous présente la pièce A, la documentation MSDN pourPOWER()
:
Syntaxe
POWER ( float_expression , y )
Arguments
float_expression
Est une expression de type float ou d'un type qui peut être implicitement converti en float.
Types de retour
Identique à float_expression
.
Vous pouvez conclure de la lecture de cette dernière ligne que POWER()
le type de retour est FLOAT
, mais relisez. float_expression
est "de type float ou d'un type qui peut être implicitement converti en float". Ainsi, malgré son nom, float_expression
peut en fait être un FLOAT
, un DECIMAL
ou un INT
. Étant donné que la sortie de POWER()
est la même que celle de float_expression
, elle peut également appartenir à l'un de ces types.
Nous avons donc une fonction scalaire avec des types de retour qui dépendent de l'entrée. Est-ce que ça pourrait être?
Observations
Je vous présente la pièce B, un test qui démontre que POWER()
sa sortie est convertie en différents types de données en fonction de son entrée .
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;
Les résultats pertinents sont:
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
Ce qui semble se produire est que les POWER()
moulages float_expression
dans le type le plus petit qui correspond, non compris BIGINT
.
Par conséquent, SELECT POWER(10.0, 38);
échoue avec une erreur de dépassement de capacité, car le 10.0
cast NUMERIC(38, 1)
n'est pas assez grand pour contenir le résultat de 10 38 . En effet, 10 38 se développe pour prendre 39 chiffres avant la décimale, tandis que NUMERIC(38, 1)
peut stocker 37 chiffres avant la décimale plus un après. Par conséquent, la valeur maximale NUMERIC(38, 1)
pouvant être maintenue est 10 37 - 0,1.
Fort de cette compréhension, je peux concocter un autre échec de débordement comme suit.
SELECT POWER(1000000000, 3); -- one billion
Un milliard (par opposition au milliard de dollars du premier exemple, qui est converti en NUMERIC(38, 0)
) est juste assez petit pour tenir dans un INT
. Un milliard élevé à la troisième puissance, cependant, est trop gros pourINT
, d'où l'erreur de débordement.
Plusieurs autres fonctions présentent un comportement similaire, où leur type de sortie dépend de leur entrée:
- Fonctions mathématiques :
POWER()
, CEILING()
, FLOOR()
, RADIANS()
, DEGREES()
etABS()
- Fonctions système et expressions :
NULLIF()
, ISNULL()
, COALESCE()
, IIF()
, CHOOSE()
et CASE
expressions
- Opérateurs arithmétiques : les deux
SELECT 2 * @MAX_INT;
et SELECT @MAX_SMALLINT + @MAX_SMALLINT;
, par exemple, entraînent des débordements arithmétiques lorsque les variables sont du type de données nommé.
Conclusion
Dans ce cas particulier, la solution est d'utiliser SELECT POWER(1e1, precision)...
. Cela fonctionnera pour toutes les précisions possibles, car 1e1
obtient cast FLOAT
, qui peut contenir des nombres ridiculement grands .
Étant donné que ces fonctions sont si courantes, il est important de comprendre que vos résultats peuvent être arrondis ou provoquer des erreurs de débordement en raison de leur comportement. Si vous attendez ou utilisez un type de données spécifique pour votre sortie, convertissez explicitement l'entrée appropriée si nécessaire.
Alors, les enfants, maintenant que vous savez cela, vous pouvez aller de l'avant et prospérer.