0
votes

SQL Server - Problème d'arrondi

Voici la partie de code que j'utilise dans une procédure stockée SQL Server.

[Time.Minimum] >= 43885.664166666664241

Cela produit cette sortie:

[Time.Minimum] >= 43885.7

qui n'est pas celle attendue et qui a un impact sur le résultat de la procédure. Je ne veux pas que cette valeur numérique soit arrondie. Je veux la valeur flottante complète que j'ai passée. Quelque chose comme ci-dessous.

DECLARE @MinimumTime FLOAT,
        @filter VARCHAR(MAX)

SET @MinimumTime = 43885.664166666664241

SELECT @filter =  COALESCE('[Time.Minimum] >= ' + CAST(@MinimumTime AS varchar(MAX)), '')
PRINT @filter

S'il vous plaît laissez-moi savoir si vous avez besoin d'informations supplémentaires.


4 commentaires

Le fait que vous ayez une variable appelée Filter où vous essayez de créer la valeur '[Time.Minimum]> = 43885.664166666664241' point très fortement à vous injecter des valeurs dans une déclaration dynamique. Cela ressemble à un problème XY . Pourquoi avez-vous besoin d'une instruction dynamique et pourquoi la paramétrez-vous ?


Vouloir «la valeur complète» pour une valeur à virgule flottante est très risqué car vous avez déjà affaire à une valeur arrondie lors de l'analyse de la constante. SELECT FORMAT (@MinimumTime, 'G38') vous donnera autant de chiffres que SQL Server peut vous en donner, mais même cela affichera uniquement 43885.664166666669 , qui ne peut pas être distingué de 43885.664166666664241 (après arrondi). Vous obtiendrez une autre valeur (différente) si vous utilisez PARSE , car cela utilise le code .NET - SELECT FORMAT (PARSE ('43885.664166666664241' AS FLOAT), 'G38') donne 43885.664166666662 .


Casting Soit de la valeur à Binary (8) vous montrera la différence entre ceux-ci est littéralement le plus petit possible ( 0x40E56db540da740d vs. code> 0x40E56db540da740e ). Je ne vais pas obtenir les résultats que vous souhaitez utiliser un float . Utilisez une chaîne, un décimal , un paramètre si vous avez une valeur exacte d'ailleurs ou changez de vos attentes. N'oubliez pas que toute représentation de caractères d'une valeur de point flottante introduit un problème de représentation avant même de vous mettre à l'analyser.


Vous ne comparez pas les flotteurs de cette façon!


3 Réponses :


3
votes

Utilisez des paramètres! C'est le seul moyen d'obtenir une valeur flottante "exacte":

declare @sql nvarchar (max);

set @sql = N'
select *
from t
where '[Time.Minimum] >= @MinimumTime
';

exec sp_executesql @sql,
                   N'@MinimumTime float',
                   @MinimumTime=@MinimumTime;

En d'autres termes, ne convertissez pas en un chaîne.


0 commentaires

1
votes

Veuillez essayer avec la requête ci-dessous de float à numérique SQL-FIDDLE : XXX

Remarque :

The basic difference between Decimal/Numeric and Float :
Float is Approximate-number data type, which means that not all values in the data type range can be represented exactly.
Decimal/Numeric is Fixed-Precision data type, which means that all the values in the data type reane can be represented exactly with precision and scale.


1 commentaires

Merci à tous pour les réponses, la plupart d'entre eux fonctionnent pour moi, mais celui-ci nécessitera le moins de changement dans le processus existant. J'espère que cela n'a aucun impact négatif sur les performances.



1
votes

Vous pouvez également utiliser

CONVERTIR

SELECT @filter =  COALESCE('[Time.Minimum] >= ' + CONVERT(NVARCHAR(30), @MinimumTime,2), '')

Mais cela vous donnera la sortie en notation scientifique.


0 commentaires