1
votes

Le formatage décimal SQL ne fonctionne pas correctement dans tous les cas

La fonction décimale de SQL Server ne fonctionne pas comme prévu.

Pour tester avec des exemples de données, j'ai créé une table et y ai inséré des valeurs. Ensuite, j'ai essayé d'exécuter une fonction décimale sur ces valeurs.

NEWVAL
-------------
16704.40
20382.13
 2683.14

Sortie:

VAL
----------
16704.405
20382.135
 2683.135

SELECT CAST(VAL AS DECIMAL(15, 2)) AS NEWVAL 
FROM TEST_VAL;

Sortie:

CREATE TABLE TEST_VAL
(
   VAL float
)

SELECT * FROM TEST_VAL

Je m'attendais au même formatage pour les 3 valeurs. Mais, pour la troisième valeur, il renvoie la valeur d'arrondi plafond.


4 commentaires

N'oubliez pas que float est approximatif. Exécutez ceci à partir d'une invite de commande Windows pour voir pourquoi les valeurs sont arrondies dans vos résultats: sqlcmd -Q "SELECT CAST (16704.405 AS float), CAST (20382.135 AS float), CAST (2683.135 AS float)" . Résultats: 16704.404999999999, 20382.134999999998, 2683.1350000000002


@ user3441903 est une réponse de ci-dessous bonne pour vous? Merci!


Oui. Gordon Linoff explique précisément. Merci.


@ user3441903 c'est génial. Vous pouvez marquer cette réponse de Gordon comme correcte. Voici comment procéder: stackoverflow.com/help/someone-answers Merci! À votre santé!


4 Réponses :


1
votes

Cela pourrait peut-être être expliqué si nous étendons la précision des trois nombres dans la première requête:

16704.40
20382.13
2683.14

Arrondir chacun des éléments ci-dessus à seulement deux décimales, ce qui correspond à un cast DECIMAL (10,2) ferait, donnerait:

16704.4050
20382.1349
2683.1351


0 commentaires

0
votes

Serait-ce utile:

select CONVERT(DECIMAL(15,2), ROUND(VAL, 2, 1)) AS NEWVAL 
from TEST_VAL;

Voici la DEMO pour SQLServer 2012: DEMO


0 commentaires

0
votes

Première question: pourquoi ils n'ont pas la même valeur?
car leur type est différent, CAST (VAL as decimal (4,2)) se formatera comme ##. ## pas ##. ### donc dans votre cas, il obtient une valeur d'arrondi plafond.

Pourquoi ne pas utiliser le même type?

SELECT CAST(VAL AS DECIMAL(8,3)) AS NEWVAL 
FROM T;

Output:

VAL
-----------
 16704.405
 20382.135
  2683.135

db fiddle ici

ou vous pouvez lancer AS DECIMAL (8, 3)

 CREATE TABLE T
 (
      [VAL] DECIMAL(8,3)
 );

 INSERT INTO T ([VAL])
 VALUES (16704.405), (20382.135), (2683.135);

 SELECT * FROM T


0 commentaires

1
votes

Ceci est dû au fait que les nombres à virgule flottante sont inexacts et sont en binaire . Mais je veux montrer comment cela fonctionne.

Le problème est qu'une décimale telle que 0,135 ne peut pas être représentée exactement. En tant que représentation en virgule flottante, ce serait généralement quelque chose comme:

0.135 --> 0.135000000004
1.135  --> 0.135000000004
2.135  --> 0.135000000004
4.135  --> 0.135000000001
8.135  --> 0.135999999997
16.135 --> 0.135999999994

(Notez que ces nombres, comme toutes les représentations de valeurs dans cette réponse, sont constitués. Ils sont destinés à soyez représentatif pour faire le point.)

Le nombre de 9 est en fait plus grand. Et les chiffres suivants ne sont que représentatifs. Dans cette représentation, nous ne verrions pas de problème avec la troncature de la valeur. Après tout, 0.1349999 devrait arrondir à la même valeur que 0.13499.

En binaire, cela semble différent:

0.135      0  11101000010101100111001110
1.135      1  11101000010101100111001110
2.135      10  1110100001010110011100111
4.135      100  111010000101011001110011
8.135      1000  11101000010101100111001
16.136     10000  1110100001010110011100
-----------^ part before the decimal
------------------^ part after the decimal
  • une grandeur. Il s’agit d’un nombre de bits représentant l’exposant.
  • une partie entière, qui est le nombre avant la virgule décimale.
  • une partie entière, qui est le nombre après la virgule décimale.

(En fait, les deux derniers sont vraiment un entier, mais je trouve beaucoup plus facile d'expliquer cela en les divisant en deux composants.)

Seul un nombre fixe de bits est disponible pour les deux parties entières. À quoi cela ressemble-t-il? Une fois de plus, les modèles représentatifs sont quelque chose comme ceci:

0.11101000010101  10011 10011 10011 10011 . . .
----------------  --------------
  ~0.135             "arbitrary" repeating pattern

Remarque: Ceci laisse de côté la partie magnitude de la représentation décimale.

Comme vous pouvez le voir , les chiffres sont coupés à la fin. Mais parfois, c'est 0 qui est coupé - il n'y a donc pas de changement dans la valeur représentée. Et parfois c'est un 1 . Et il y a un changement.

Avec cela, vous pourrez peut-être voir comment les valeurs fluctuent essentiellement, par exemple:

 0.134999999234243423

Celles-ci sont ensuite arrondies différemment , ce que vous voyez.

J'ai rassemblé ce petit db violon , afin que vous puissiez voir comment l'arrondi change autour des puissances de deux.


0 commentaires