Вопросы сравнения с плавающей запятой MySQL

18

Я столкнулся с проблемой, представив столбцы с плавающей запятой в схеме базы данных MySQL, что сравнения значений с плавающей запятой не всегда возвращают правильные результаты.

1 - 50,12
2 - 34,57
3 - 12,75
4 - ... (все остальные менее 12.00)

SELECT COUNT(*) FROM 'users' WHERE 'points' > "12.75"

Это возвращает меня «3».

Я читал, что сравнение значений с плавающей запятой в MySQL - это плохая идея, а десятичный тип - лучший вариант.

Есть ли у меня какая-либо надежда на продвижение по типу с плавающей точкой и правильное выполнение сравнений?

    
задан Sharief Shaik 02.04.2010 в 17:22
источник
  • Какие типы литералов заключены в двойные кавычки в SQL? –  Joey 02.04.2010 в 17:25
  • К сожалению, MySQL позволяет двойным кавычкам действовать как одиночные кавычки по умолчанию. Эта функция может быть отключена с помощью опции ANSI_QUOTES, которая заставит их ссылаться на идентификаторы в соответствии со стандартом ANSI SQL (например, нестандартные обратные выходы в вышеуказанном запросе). –  bobince 02.04.2010 в 17:56
  • 12.75 точно представлен в двоичном (1100.11), поэтому я не вижу, как он проходит тест «> 12.75». Вы уверены, что в вашем списке нет другой точки> 12,75? –  Rick Regan 04.04.2010 в 00:43

6 ответов

23

Вы заметили проблему ниже?

CREATE TABLE a (num float);

INSERT INTO a VALUES (50.12);
INSERT INTO a VALUES (34.57);
INSERT INTO a VALUES (12.75);
INSERT INTO a VALUES (11.22);
INSERT INTO a VALUES (10.46);
INSERT INTO a VALUES (9.35);
INSERT INTO a VALUES (8.55);
INSERT INTO a VALUES (7.23);
INSERT INTO a VALUES (6.53);
INSERT INTO a VALUES (5.15);
INSERT INTO a VALUES (4.01);

SELECT SUM(num) FROM a;
+-----------------+
| SUM(num)        |
+-----------------+
| 159.94000005722 | 
+-----------------+

Между некоторыми из этих строк есть дополнительный 0.00000005722 . Поэтому некоторые из этих значений будут возвращать false по сравнению со значением, с которым они были инициализированы.

Чтобы избежать проблем с арифметикой с плавающей запятой и сравнениями, вы должны использовать тип данных DECIMAL :

ALTER TABLE a MODIFY num DECIMAL(6,2);

SELECT SUM(num) FROM a;
+----------+
| SUM(num) |
+----------+
|   159.94 | 
+----------+
1 row in set (0.00 sec)
    
ответ дан Daniel Vassallo 02.04.2010 в 17:32
  • Эй, Даниэль! Благодарю. Я рассматриваю возможность преобразования моего типа столбца в DECIMAL. –  Sharief Shaik 02.04.2010 в 18:39
  • @Sharief: если преобразование в DECIAML невозможно, единственная опция, которую я вижу, - это разрешить некоторый допуск для сопоставлений с плавающей запятой, чтобы вы могли написать свой запрос следующим образом: SELECT COUNT (*) FROM users WHERE points> (12.75 + 0,001); ... Однако, если точность имеет первостепенное значение, то неподвижная точка DECIMAL - это путь. Другой альтернативой DECIMAL может быть использование целочисленного значения, масштабированного для представления ваших значений с точки зрения сотых: 5012 вместо 50.12. Могут быть ситуации, когда это может быть уместно. –  Daniel Vassallo 02.04.2010 в 18:48
  • Я попытался добавить терпимость уже, точно так, как вы упомянули, даже тогда результаты никогда не были согласованы. –  Sharief Shaik 02.04.2010 в 21:51
  • DECIMAL не является правильным выбором в каждом контексте ... Прочитайте это: stackoverflow.com/a/5150314/655224. В моем случае я сравнил два значения float с ... WHERE CAST (float1 AS CHAR) <= CAST (float2 AS CHAR)? –  algorhythm 29.05.2015 в 13:43
2

Я столкнулся с подобной проблемой один раз. Преобразуйте поле «float» в «decimal». Это определенно решит проблему.

    
ответ дан intellidiot 05.04.2010 в 09:16
  • Я думал, что с помощью точной фиксированной длины поплавка уже решена проблема, так что это не так? например; i определить float (4,2). И затем я сохранил значение 12.50, а затем я попытаюсь сравнить его с выражением «> 12.50». Разве он не потерпит неудачу? –  gumuruh 07.02.2012 в 05:08
1

Это плавающая точка, так что в чем проблема? 3 может быть правильным результатом, зависит от того, что база данных думает о 12.75. Это 12,75 или немного больше?

Используйте DECIMAL, если вы хотите точные цифры.

    
ответ дан Frank Heikens 02.04.2010 в 17:26
  • Привет, Фрэнк, не могли бы вы рассказать о том, что вы подразумеваете под «то, что база данных думает о 12.75». Должен ли я быть в затруднении, если бы попытался сравнить двухзначное прецизионное значение с точностью до трех цифр. Как ... SELECT COUNT (*) FROM users WHERE points> "12.751" –  Sharief Shaik 02.04.2010 в 18:35
  • @ShariefShaik Я думаю, что Decimal должен был решить этот случай, исходя из того, что испытывает другой пользователь. –  gumuruh 07.02.2012 в 05:10
1

Есть проблемы с сопоставлением поплавков для равенства. Это может дать непредсказуемые результаты. Это связано с внутренней реализацией арифметики с плавающей запятой.

    
ответ дан Andrey 02.04.2010 в 17:27
1

Я делаю это

WHERE abs(value - 12.75)<0.001

, но я согласен, любой язык может сравнивать равенство float, и если сохраненные значения равны точным значениям чисел, которые вы вставили, не должно быть никаких проблем

только с несколькими десятичными знаками и точными значениями соответствия, точные ошибки не кажутся очевидной причиной таких несоответствий в MySQL

    
ответ дан ninja 07.04.2017 в 09:02
0

Сравнение числа со строкой?

    
ответ дан dkretz 02.04.2010 в 17:28