2010-06-11 12 views
3

Je comprends l'ensemble des problèmes dans la comparaison des flotteurs, et déplore leur utilisation dans ce cas - mais je ne suis pas l'auteur de la table et n'ai qu'un petit obstacle à gravir ...TSQL - faire une valeur float littérale

Quelqu'un a décidé d'utiliser des flottants comme vous vous attendez à ce que les GUID soient utilisés. J'ai besoin de récupérer tous les enregistrements avec une valeur flottante spécifique.

sp_help MyTable 

-- Column_name Type Computed Length Prec 
-- RandomGrouping float no 8 53 

Voilà ma tentative naïve:

--yields no results 
SELECT RandomGrouping 
FROM MyTable 
WHERE RandomGrouping = 0.867153569942739 

Et voici une tentative de travail environ:

--yields 2 records 
SELECT RandomGrouping 
FROM MyTable 
WHERE RandomGrouping BETWEEN 0.867153569942739 - 0.00000001 
     AND 0.867153569942739 + 0.00000001 

-- 0.867153569942739 
-- 0.867153569942739 

Dans ma tentative naïve, est qu'un littéral virgule flottante littéral? Ou est-ce vraiment un littéral décimal qui est converti plus tard?

Si mon littéral n'est pas un littéral en virgule flottante, quelle est la syntaxe pour faire un littéral en virgule flottante?

EDIT: Une autre possibilité m'est venue à l'esprit ... il se peut qu'un nombre plus précis que celui affiché soit stocké dans cette colonne. Il peut être impossible de créer un littéral qui représente ce nombre. J'accepterai des réponses qui démontrent que c'est le cas.


EDIT: réponse à DVK. TSQL est le dialecte SQL de MSSQLServeur.

Ce script fonctionne, et ainsi l'égalité peut être réalisée entre les types de manière déterministe float:

DECLARE @X float 
SELECT top 1 @X = RandomGrouping 
FROM MyTable 
WHERE RandomGrouping BETWEEN 0.839110948199148 - 0.000000000001 
    AND 0.839110948199148 + 0.000000000001 
    --yields two records 
SELECT * 
FROM MyTable 
WHERE RandomGrouping = @X 

Je dis « approximativement » parce que les tests de méthode pour une gamme. Avec cette méthode, je pourrais obtenir des valeurs qui ne sont pas égales à ma valeur prévue.

L'article lié ne s'applique pas car je n'essaie pas (intentionnellement) de chevaucher les limites du monde entre les virgules décimale et flottante. J'essaye de travailler avec seulement des flotteurs. Il ne s'agit pas de la non-convertibilité des nombres décimaux en flottants.


Réponse à Zinglon:

Une valeur littérale qui peut trouver mes dossiers, merci.

DECLARE @Y binary(8) 
SET @Y = 0x3FEAD9FF34076378 

SELECT * 
FROM MyTable 
WHERE convert(binary(8), RandomGrouping) = @Y 

Répondre

1

Il est possible que les valeurs sont tronquées à l'affichage. Je suppose que la colonne n'a pas de contrainte unique, sinon la question serait sans objet. Sur ma configuration, SSMS tronque la valeur plus précise dans ce script.

create table flt (f float not null primary key) 
insert into flt 
select 0.111111111111111 
union all 
select 0.1111111111111111 
select f, cast(f as binary(8)) from flt 

De même, si ces valeurs sont distinctes, vous pouvez les entraînes en binaire (8) et les identifier en fonction de cette valeur, comme celui-ci:

select f from flt 
where cast(f as binary(8)) = 0x3FBC71C71C71C71C 
0

Le problème n'est pas de savoir s'il s'agit d'un littéral en virgule flottante ou non. Le problème est que comparer deux flotteurs pour l'égalité dans Sybase (ou n'importe quel serveur DB) n'est pas déterministe, puisque 4.00000000000000000000 ... et 3.99999999999999999999 ... sont le même nombre exact mais ne sont pas égaux.

Votre deuxième solution est la seule façon correcte de comparer les flottants pour «égalité» (c'est-à-dire, sont-ils les mêmes jusqu'à une précision). Pourquoi dites-vous «travailler approximativement» à propos de votre deuxième approche?

Puisque vous n'avez pas fourni l'écriture en place un serveur de base de données spécifique que vous utilisez, voici une assez bonne du problème (avec essentiellement les mêmes conclusions que ci-dessus) pour MySQL

http://dev.mysql.com/doc/refman/5.0/en/problems-with-float.html