Задавайте вопросы, мы ответим
Вы не зашли.
Здравствуйте,
в таблице (7800 элементов) есть 2 поля тип "float"
поле `pcdd`, значения рядов (для примера):
"100"
"110"
"114.3"
Запрос: SELECT * FROM `table` WHERE `pcdd` = 114.3 - "ноль рядов" !!!
Запрос: SELECT * FROM `table` WHERE `pcdd` = 100 - "1 ряд"
Запрос: SELECT * FROM `table` WHERE `pcdd` LIKE 114.3 - "1 ряд"
Вопрос, почему не ищет точно по значению "114.3" ?
Помогите пожалуйста, всю голову уже сломал...
PS База во вложении
Неактивен
Это особенность представления чисел в компьютере, связанная с округлением.
Например,
[silentia] root (none) > SELECT 2/3, 2/3 - 0.6667, 2/3 = 0.6667; +--------+--------------+--------------+ | 2/3 | 2/3 - 0.6667 | 2/3 = 0.6667 | +--------+--------------+--------------+ | 0.6667 | 0.0000 | 0 | +--------+--------------+--------------+ 1 row in set (0.00 sec)
С одной стороны, компьютер округляет 2/3 до 0.6667 и разность чисел
равна нулю. Но на самом деле она нулю не равна (там шесть в периоде),
и поэтому числа не равны. Различаются они каким-то знаком, который
мы уже не видим, но который есть.
При сравнении FLOAT и DOUBLE есть одно правило: через равенство их
сравнивать нельзя.
Неактивен
В принципе, это все объясняет.
Тогда другой вопрос, кокой тип поля использовать для хранения этих значений чтобы потом делать выборку через равенство?
Отредактированно ebuilder (04.02.2011 13:31:13)
Неактивен
Дело не в типе поля. Как Вы считаете — нужно ли выводить строку
WHERE `pcdd` = 114.3001? а `pcdd` = 114.3000000000000000000000001?
Неактивен
Ну к примеру если у меня значения строк:
100
114
114.3
115
139.7
148
мне нужно отобрать 1 строку которая к примеру, именно 114.3 или 139.7, как быть? возможно через ROUND запрос строить?
Неактивен
Для такого хранения данных можно использовать, например, BETWEEN 114.25 AND 114.34.
А что Вы храните в этой колонке, если не секрет, что по ней приходится искать?
Неактивен
Это параметры автомобильных дисков, в данном случае расстояние между отверстиями под болты.
Мне нужно выбрать например все диски с такими параметрами из 1 таблицы:
7J16, 4x114.3, ET40, DIA73.1
т.е.
7 - ширина диска
16 - диаметр
4 - количество болтов
114.3 - расстояние между болтами
40 - вылет диска
73.1 - размер ступицы
И все это мне нужно поместить в 1 запрос
SELECT * FROM `table` WHERE `w`= '7' AND `D`= '16' AND `pcdc`= '4' AND `pcdd`= '114.3' AND `ET`= '40' AND `DIA`= '73.1' - разумеется не работает
Ну вот, `w`-ширина и `pcdd`-расстояние между дырками и `ET` - вылет и `DIA`- размер ступицы - все они типа FLOAT)
Как будет выглядеть такой запрос?
Менять тип поля всетаки не вариант, так как придется еще поля сравнивать > и < - для некоторых выборок..
вот такой вариант попробовал:
SELECT * FROM `table` WHERE ROUND(w, 2)= 7 AND ROUND(D, 2)= 16 AND ROUND(pcdc, 2)= 4 AND ROUND(pcdd, 2)= 114.3 AND ROUND(ET, 2)= 40 AND ROUND(DIA, 2)= 73.1 - работает, но выглядит страшновато, и вопрос потери в производительности....
Корректно ли это?
Вообще, между нами говоря я как и многие, стал жертвой математических законов) На самом деле, "не целые" значения полей для данной задачи имеют тот же смысл что и "целые", просто уж так вышло что они "не целые". В итоге теперь такой геморой.
Отредактированно ebuilder (06.02.2011 12:43:30)
Неактивен
Вот последний абзац мне нравится у Вас больше всего. Вы действительно обращаетесь
с этими значениями как с целыми — так и храните их как целые (1143, например)? А
запятую перед последней цифрой просто добавляйте при выдаче.
Никогда не думал, что расстояние между болтами выставляется с точностью до десятых
долей миллиметра... там правда такая точность нужна?
Неактивен
К сожалению, вариант умножения всех значений в колонке на 10 - неподходит, т.е. есть значения до 100тых, ныпример 107,95
(11430, 10795, ...) - придется умножать все на 100 и делать поле integer, и опять же как потом сравнивать < > ...
>Никогда не думал, что расстояние между болтами выставляется с точностью до десятых
>долей миллиметра... там правда такая точность нужна?
думаю что точность до 100 долей и не оч нужна, но к сожалению приходится считаться с общепринятыми техническими характеристиками..
Все-таки, склоняюсь к варианту:
SELECT * FROM `table` WHERE ROUND(w, 2)= 7 AND ROUND(D, 2)= 16 AND ROUND(pcdc, 2)= 4 AND ROUND(pcdd, 2)= 114.3 AND ROUND(ET, 2)= 40 AND ROUND(DIA, 2)= 73.1
Скажите пожалуйста, на сколько такой запрос будет тормозить работу?
Отредактированно ebuilder (06.02.2011 13:33:00)
Неактивен
А набор значений — фиксированный? Просто если есть два десятка стандартов,
то можно обойтись ENUM('73.1', '114.3', ...) — оно будет вести себя как строка,
но при этом храниться будет как число. Если нет — тогда, видимо, нужно будет
хранить, как строки
Как DOUBLE точно хранить не стоит, потому что если вдруг получите 114.2999 —
будет некрасиво
Неактивен
набор значений — фиксированный, но ENUM - опять же непойдет, как сравнивать значения на < > - больше меньше?
повторюсь),
что все-таки, склоняюсь к варианту:
SELECT * FROM `table` WHERE ROUND(w, 2)= 7 AND ROUND(D, 2)= 16 AND ROUND(pcdc, 2)= 4 AND ROUND(pcdd, 2)= 114.3 AND ROUND(ET, 2)= 40 AND ROUND(DIA, 2)= 73.1
Скажите пожалуйста, на сколько такой запрос будет тормозить работу?
Неактивен
Ну, он никогда не будет использовать индексы. В остальном — нормальный.
Больше-меньше для ENUM вполне работают, надо только разместить размеры
в порядке увеличения.
Кстати, я совсем забыл — можно попробовать использовать DECIMAL — тот
же FLOAT, но без ошибок округления.
Неактивен
Тип полей DECIMAL - работает, при значении DECIMAL(5,2) - 2 знака после запятой.
Дробные числа в базе стали вида 114.30, 73.10 ....
целые числа в базе стали вида 102.00, 57.00 ну и т.д.
SELECT * FROM `table` WHERE `pcdc`= 4 AND `pcdd`= 114.3 AND `ET`= 40 AND `DIA`= 73.1
выборка по равенству работает, индексы вроде тоже!
paulus большое спасибо!
Всем удачи!
Отредактированно ebuilder (06.02.2011 23:51:10)
Неактивен