J'exécute SQL Server 2012
SELECT
0.15 * 30 / 360,
0.15 / 360 * 30
Résultats:
0.012500,
0.012480
Celui-ci est même plus déroutant pour moi:
DECLARE @N INT = 360
DECLARE @I DECIMAL(38,26) = 0.15 * 30 / 360
DECLARE @C DECIMAL(38,26) = 1000000
SELECT @C * @I * POWER(1 + @I, @N) / ( POWER(1 + @I, @N) - 1 )
SELECT @C * (@I * POWER(1 + @I, @N) / ( POWER(1 + @I, @N) - 1 ) )
La première sélection me donne le résultat correct: 12644.44022 La seconde tronque le résultat: 12644.00000
sql-server
sql-server-2012
t-sql
decimal
cpacheco
la source
la source
Réponses:
La détermination de la précision et de l'échelle résultant des expressions est un nid de rat et je ne pense pas que quiconque comprenne les règles exactes dans chaque scénario, en particulier lors du mélange décimal (ou flottant!) Et int. Voir cette réponse par gbn .
Vous pouvez bien sûr adapter les expressions pour vous donner ce que vous voulez en effectuant des conversions explicites beaucoup plus verbeuses. C'est probablement exagéré mais:
Aucun des deux résultats n'est arrondi à tort en raison d'un calcul en virgule flottante cassé ou d'une précision / échelle extrêmement erronée.
la source
Comme Aaron Bertrand l'a mentionné, les expressions sont très difficiles à prévoir.
Si vous osez y aller, vous pouvez essayer d'obtenir un aperçu en utilisant l'extrait de code suivant:
Voici le résultat:
la source
Malgré les excellentes réponses déjà ajoutées à cette question, il existe un ordre de priorité explicitement défini pour la conversion des types de données dans SQL Server.
Lorsqu'un opérateur combine deux expressions de types de données différents, les règles de priorité des types de données spécifient que le type de données avec la priorité la plus faible est converti en type de données avec la priorité la plus élevée. Si la conversion n'est pas une conversion implicite prise en charge, une erreur est renvoyée. Lorsque les deux expressions d'opérande ont le même type de données, le résultat de l'opération a ce type de données.
SQL Server utilise l'ordre de priorité suivant pour les types de données:
Ainsi, par exemple, si vous
SELECT 0.5 * 1
(en multipliant une décimale par un int) vous obtenez un résultat qui est converti en une valeur décimale, car la prioritédecimal
est plus élevée que leint
type de données.Voir http://msdn.microsoft.com/en-us/library/ms190309.aspx pour plus de détails.
Cela dit, cela
SELECT @C * (@I * POWER(1 + @I, @N) / (POWER(1 + @I, @N) - 1 ));
devrait probablement renvoyer une valeur décimale, car pratiquement toutes les entrées sont décimales. Fait intéressant, vous pouvez forcer un résultat correct en le modifiantSELECT
pour:Cela renvoie:
Je n'arrive pas à expliquer en quoi cela fait une différence, bien que ce soit clairement le cas . Ma supposition est que
1E0
(un flottant explicite) dans laPOWER(
fonction force SQL Server à faire un choix différent sur les types de sortie pour laPOWER
fonction. Si ma supposition est correcte, cela indiquerait un bogue possible dans laPOWER
fonction, puisque la documentation indique que la première entrée dePOWER()
est un flottant, ou un nombre qui peut être implicitement converti en flottant.la source
Connaissez-vous la
SELECT .. INTO
syntaxe ? C'est une astuce utile pour déconstruire des situations comme celle-ci car elle crée une table à la volée avec juste les bons types de données pour laSELECT
liste donnée .Vous pouvez diviser votre calcul en ses étapes constitutives, en appliquant les règles de priorité des serveurs SQL au fur et à mesure, pour voir comment la définition change. Voici à quoi ressemblerait votre premier exemple:
Voici la sortie:
la source
(1+1)
et2
sont de typeint
mais cette question a un exemple où ils finissent par produire un résultat typé différemment.