Database
 sql >> Base de données >  >> RDS >> Database

SQL FLOAT :3 points qui vous aideront à éviter les erreurs mathématiques étranges

Avez-vous déjà pensé que SQL pouvait se tromper en mathématiques ? Cela semble fou. Mais si vous avez utilisé le type de données SQL FLOAT, vous avez peut-être rencontré les problèmes que je vais vous montrer.

Considère ceci. 0,1 + 0,2 devrait être 0,3, n'est-ce pas ? Mais vérifiez cela en utilisant le type de données SQL FLOAT.

DECLARE @f1 FLOAT = 0.1
DECLARE @f2 FLOAT = 0.2

SELECT CASE WHEN @f1 + @f2 = .3 THEN 1 ELSE 0 END

Le résultat correct est 1. Mais vérifiez la figure 1.

Ai-je votre attention maintenant ? Je l'espère bien. C'est assez effrayant de dépendre d'un système qui ne nous donne pas de calculs corrects. Mais cet article vous aidera à éviter cela.

Il y a du travail à faire. Nous devons partir de ce qu'est un type de données FLOAT.

Qu'est-ce que le type de données SQL FLOAT ?

Le type de données SQL FLOAT est un type de données numérique approximatif utilisé pour les nombres à virgule flottante. Ils peuvent stocker des nombres très grands ou très petits. Ils sont également utilisés pour les calculs nécessitant des temps de traitement rapides.

Tout cela se fait au prix d'une perte de précision. De plus, vous ne pouvez pas dire où la virgule sera placée après le calcul - elle flotte . Pendant ce temps, les nombres exacts comme DECIMAL auront une position décimale fixe.

Comment déclarer un type de données SQL FLOAT

La syntaxe est FLOAT[(n)], où n est le nombre de bits utilisés pour stocker la mantisse d'un nombre à virgule flottante en notation scientifique. Cela dicte également la précision et la taille de stockage. Les valeurs possibles pour n sont compris entre 1 et 53. Notez que n est facultatif.

Voici un exemple :

DECLARE @floatValue1 FLOAT;   -- Float variable without the number of bits
DECLARE @floatValue2 FLOAT(3) -- Float variable with 3 bits 

Si vous ne spécifiez pas n , la valeur par défaut est 53. C'est également la valeur maximale. De plus, FLOAT(53) est un nombre à virgule flottante double précision ou binaire64. En plus d'utiliser FLOAT(53), vous pouvez également le déclarer comme DOUBLE PRECISION.

Les 3 déclarations suivantes sont fonctionnellement équivalentes :

DECLARE @double1 FLOAT(53); 
DECLARE @double2 FLOAT;
DECLARE @double3 DOUBLE PRECISION;

Le tableau indique le nombre de bits et la taille de stockage correspondante.

Valeur de n Taille de stockage
1 à 24 4 octets
25 à 53 8 octets

SQL FLOAT et REAL sont-ils identiques ?

REAL est également FLOAT(24). Il est également appelé simple précision ou binaire32.

Pourquoi le savoir est important

Le fait de savoir qu'il s'agit d'un nombre approximatif vous empêchera de l'utiliser pour des calculs nécessitant de la précision. Êtes-vous également préoccupé par le stockage et la mémoire? Utilisez REAL ou FLOAT(24) si vous n'avez pas besoin de valeurs trop grandes ou trop petites.

Quelles sont les différences entre FLOAT et DECIMAL ?

FLOAT est un nombre approximatif. DECIMAL est un nombre exact. Voici un résumé des différences dans un tableau :

Opérateurs
FLOTTER DECIMAL
Point décimal Peut être placé n'importe où dans le chiffre Position fixe
Limite maximale 38 chiffres ou 99 999 999 999 999 999 999 999 999 999 999 999 999 FLOAT(53) a une plage maximale de 1,79E+308 ou 179 suivi de 306 zéros
Stockage Maximum de 8 octets Maximum de 17 octets
Résultat de calcul Approximatif Exact
Vérifications comparatives N'utilisez pas =ou <>. A éviter lors des arrondis=ou <>. Bon pour arrondir

Vous avez déjà vu dans la figure 1 comment le calcul d'un nombre FLOAT peut avoir des résultats étranges. Si vous changez le type de données en DECIMAL comme ceci :

DECLARE @d1 DECIMAL(2,1) = 0.1
DECLARE @d2 DECIMAL(2,1) = 0.2

SELECT CASE WHEN @d1 + @d2 = 0.3 THEN 1 ELSE 0 END 

Le résultat sera correct.
L'utilisation d'un opérateur d'inégalité est également un problème. Découvrez la boucle ci-dessous.

DECLARE @floatValue FLOAT(1) = 0.0

WHILE @floatValue <> 5.0
BEGIN
	PRINT @floatValue;
	SET @floatValue += 0.1;
END 

Qu'en penses-tu? Voir Figure 2 ci-dessous.

Boom! Boucle infinie! La condition d'inégalité sera toujours vraie. Donc, le choix logique est de changer le type en DECIMAL.

DECLARE @decimalValue DECIMAL(2,1) = 0.0

WHILE @decimalValue <> 5.0
BEGIN
	PRINT @decimalValue;
	SET @decimalValue += 0.1;
END 

Le code ci-dessus s'arrêtera sûrement lorsque @decimalValue est égal à 5,0. Voyez par vous-même dans la figure 3 ci-dessous.

Joli! Mais si vous insistez toujours sur FLOAT, cela fonctionnera très bien sans la boucle infinie.

DECLARE @floatValue FLOAT(1) = 0.0

WHILE @floatValue < 5.0
BEGIN
	PRINT @floatValue;
	SET @floatValue += 0.1;
END

Pendant ce temps, l'arrondi est également désactivé. Considérez ce qui suit :

DECLARE @value FLOAT(2) = 1.15

SELECT ROUND(@value, 1)  -- This will result to 1.1

Au lieu de 1.20, le code donne 1.1. Mais si vous utilisez DECIMAL, le résultat sera correct.

DECLARE @value DECIMAL(3,2) = 1.15

SELECT ROUND(@value, 1)  -- This will result in 1.2 or 1.20

Lorsque FLOAT est correct et que DECIMAL n'est pas

Les chiffres exacts ne sont-ils PAS si exacts tout le temps ? Pour reproduire ce problème, nous allons utiliser un calcul, puis nous l'inverserons. Tout d'abord, préparons les données.

CREATE TABLE ExactNumerics1
(
	fixed1 DECIMAL(8,4),
	fixed2 DECIMAL(8,4),
	fixed3 DECIMAL(8,4),
	calcValue1 AS fixed3 / fixed1 * fixed2
)
GO

INSERT INTO ExactNumerics1
(fixed1,fixed2,fixed3)
VALUES
(54,0.03,1*54/0.03)

Le tableau ci-dessus utilisera des valeurs fixes pour les 2 premières colonnes. La troisième colonne contiendra le calcul. Enfin, la quatrième, qui est une colonne calculée, fera le calcul inverse. Le résultat correct dans la colonne calculée doit être 1.

Maintenant, pour le comparer à FLOAT, créons une table et des données similaires.

CREATE TABLE ApproxNumerics1
(
	float1 FLOAT(2),
	float2 FLOAT(2),
	float3 FLOAT(2),
	calcValue1 AS float3 / float1 * float2 
)

INSERT INTO ApproxNumerics1
(float1, float2, float3)
VALUES
(54,0.03,1*54/0.03)

Interrogeons.

SELECT * FROM ApproxNumerics1
SELECT * FROM ExactNumerics1

Les resultats? Consultez la figure 4.

Que s'est-il passé ici? FLOAT a bien compris, mais pas DECIMAL. Quelque chose s'est mal passé.

LA CONVERSION IMPLICITE LE FAIT ENCORE

La conversion implicite se produit parce que SQL est indulgent. Lorsque différents types de données sont utilisés dans un calcul, SQL Server essaie de le convertir en utilisant une conversion implicite dans notre dos.

Une conversion a-t-elle vraiment eu lieu ? De plus, chaque colonne de ExactNumerics1 table est un DECIMAL.

Vérifions la structure de la table de ExactNumerics1 table dans SQL Server Management Studio :

Remarquez la zone encadrée en rouge dans la figure 3. La colonne calculée est un DECIMAL(30,17), et non un DECIMAL(8,4). Selon la documentation officielle, 2 colonnes DECIMAL avec une précision et une échelle différentes correspondent à 2 types de données différents . Voyez par vous-même ici. En raison de la différence, une conversion est nécessaire. Ainsi, la conversion implicite entre en jeu.

Et s'ils sont différents et qu'une conversion implicite s'est produite ?

Encore une fois, d'après la documentation officielle, une perte de précision ou d'échelle peut se produire lors de la conversion implicite . Ainsi, un CAST explicite est requis. Notez le type de données DECIMAL dans la table de conversion de cette référence.

Une perte vient de se produire ici. Si la colonne calculée est également DECIMAL(8,4), la conversion implicite ne se produit pas.

Pour éviter la conversion implicite, suivez la documentation officielle. La structure du tableau aurait dû ressembler à ceci :

CREATE TABLE ExactNumerics2
(
	fixed1 DECIMAL(8,4),
	fixed2 DECIMAL(8,4),
	fixed3 DECIMAL(8,4),
	calcValue1 AS CAST(fixed3 / fixed1 * fixed2 AS DECIMAL(8,4)) -- the explicit CAST
)

Le CAST explicite dans la colonne calculée garantit que les types de données sont cohérents. Si nous suivons également cette structure et insérons les mêmes données, le résultat sera correct. Découvrez la nouvelle sortie dans la figure 6 ci-dessous.

Finalement, les chiffres exacts ne seront pas exacts si une conversion implicite se produit entre 2 ou plusieurs valeurs DECIMAL.

Pourquoi le savoir est important

Cela vous donne une idée de ce dont vous avez besoin pour vos tables et vos variables. De plus, la conversion implicite peut rendre fous même les nombres exacts. Par conséquent, définissez explicitement la précision et l'échelle et soyez cohérent avec celles-ci dans vos calculs.

Dois-je utiliser SQL FLOAT pour les données financières ?

Lors du calcul des pourcentages dans chaque tranche d'un graphique à secteurs, la somme doit être de 100 %. Les totaux des rapports récapitulatifs et détaillés doivent également être cohérents. Si la précision des résultats est cruciale, un type de données approximatif comme FLOAT ne fera pas l'affaire. Le choix logique pour cela est DECIMAL.

Mais une question demeure.

Quand devez-vous utiliser FLOAT ?

Utilisez FLOAT pour les données qui nécessitent des valeurs astronomiques comme les distances entre les galaxies. Pendant ce temps, le type de données DECIMAL subira un débordement arithmétique avec ce type de données. De minuscules valeurs comme le diamètre d'un noyau atomique conviendront également à l'aide de FLOAT. Les données scientifiques et autres valeurs qui ne nécessitent pas de précision peuvent également bénéficier de FLOAT.

Pourquoi le savoir est important

Nous ne disons pas que FLOAT est mauvais et DECIMAL est bon ou vice versa. Connaître les cas d'utilisation corrects pour chacun vous donnera, à vous et à vos utilisateurs, les résultats escomptés. Et encore une fois, vous voulez que vos utilisateurs soient heureux, n'est-ce pas ?

Conclusion

À la fin de la journée, nous voulons tous faire notre travail et le faire bien. Les maths feront toujours partie de nos métiers. Et connaître les types de données numériques corrects nous aidera également à y faire face. Ce n'est pas difficile si vous savez ce que vous faites.

J'espère que cet article vous a aidé à éviter les calculs bizarres dans SQL Server.

Avez-vous quelque chose à ajouter? Ensuite, faites-le nous savoir dans la section Commentaires. Partagez-le également sur vos plateformes de médias sociaux préférées.