SQL-запрос выбора с десятичным / плавающим сравнением не работает - PullRequest
4 голосов
/ 07 апреля 2011

Мне нужно выполнить десятичные операции сравнения, используя простой выбор, например:

select * from table_a, где время> 0,0004

идентификатор времени


00.000502
1 0.000745
2 0.000725
4 0.000197
5 0.000176
6 0.000833
7 0.000269
8 0.000307
9 0.000302

Результат содержитзначения, которые удовлетворяют сравнению.В нескольких словах, «время> 0,0004» всегда оценивается как истинное, а «время <0,0004» всегда оценивается как ложное.</p>

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

Если я использую подзапрос, он выполняет запрос правильно:

select* из таблицы, где время> (выберите время из таблицы, где идентификатор = 8);

время ID


0 0,000502
1 0,000745
2 0,000725
60.000833

Создание таблицы:

CREATE TABLE "table_a" (целое число "id" NOT NULL ПЕРВИЧНЫЙ КЛЮЧ, десятичное число "time" NOT NULL);

Ответы [ 5 ]

5 голосов
/ 08 апреля 2011

Благодаря всем вашим предложениям я нашел корень проблемы:

Значения столбца «время» обрабатывались как «текст».Почему?

Я импортировал данные в таблицу, используя «.import», и мой CSV-файл содержал пробелы вокруг десятичных значений.Так или иначе, команда импорта SQLite позволяет вставкам произойти, даже если типы не совпадают.После того, как я удалил пробелы из CSV-файла, данные вставляются как «реальные», что позволяет проводить сравнения чисел правильно.ОДНАКО, это не объясняет, почему данные в столбце «десятичные» имеют тип «реальные», а не «десятичные» или «числовые», как объяснено в их документах: http://www.sqlite.org/datatype3.html

select id, time, typeof(time) from table_a;
id    time           type
----  -------------  ----
0      0.000502      text
1      0.000745      text
2      0.000725      text
4      0.000197      text
5      0.000176      text
6      0.000833      text
7      0.000269      text
8      0.000307      text
9      0.000302      text

select id, time, typeof(time) from table_b;
id    time           type
----  -------------  ----
0     0.000502       real
1     0.000745       real
2     0.000725       real
4     0.000197       real
5     0.000176       real
6     0.000833       real
7     0.000269       real
8     0.000307       real
9     0.000302       real
4 голосов
/ 07 апреля 2011

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

При попытке сравнить строку и число, если строка не является правильно сформированным числом, она считается больше, чем число.

Поэтому очевидно, что по какой-то причине этизначения времени на самом деле не числа, а строки.Это озадачивает по двум причинам.(1) Поскольку столбец time имеет тип decimal, он должен иметь «числовое» сходство, которое должно хранить в нем все, что выглядит как число, преобразованное в число.(2) Даже если значения были сохранены как строки, они все равно должны были быть преобразованы в числа для сравнения с 0,0004.

Почему они не могли быть преобразованы?Возможность № 1: возможно, они содержат дополнительные пробелы или что-то в этом роде.Возможность # 2: возможно, ваша локаль хочет использовать что-то кроме . в качестве десятичной точки.(Вполне могут быть и другие возможности, о которых я не задумывался.)

Если вы вставляете запись в таблицу, которая на самом деле содержит число - insert into table_a (id,time) values (999,0.0001) или что-то в этом роде - выполняет эту записьбыть включенным в ваш выбор?

2 голосов
/ 28 августа 2014

Старый вопрос, но я хочу дать другой ответ.

Поскольку SQLite все видит в тексте, происходит следующее:

Если вы запросите ... where a < 1000, он ничего не найдет, если a будет рассматриваться как текст

если вы запросите ... where a < '1000', он будет сравнивать тысячу как некоторый текст и будет иметь проблемы, если числа имеют разную длину символов. 1000 - 4 символа, 100 - 3 и т. Д.

Но есть выражение CAST http://www.sqlite.org/lang_expr.html#castexpr

так что ... where cast(a as Integer) < 1000 приведет к тому, что вы хотите (может быть сделано с REAL для float)

1 голос
/ 06 января 2016

Очевидно, что это был не ваш случай, но имейте в виду, что иногда некоторые инструменты администрирования (например, SQLite Administrator или SQLite Expert ) могут показывать вам реальные значения как равные, хотя онине.Вот пример:

Number Comparison

Разница незначительна, но, вероятно, достаточно, чтобы причинить вам сильную головную боль.

0 голосов
/ 07 апреля 2011

Я не могу воспроизвести поведение, которое вы видите. Я получаю правильные результаты, даже если я

  • определить столбец времени как varchar,
  • вставить значение в одинарные кавычки,
  • вставить значение в двойных кавычках,
  • определить столбец времени как десятичное и сначала вставьте текстовые литералы ('тестовый текст')

Но, как и Сэмюэль Нефф, я все еще хотел бы видеть результат SELECT id, time, typeof(time) FROM table_a; в вашей базе данных. Вы знаете, что еще может быть интересным? Результат

select * from table_a order by time;

Эти результаты относятся к версии 3.7.4, которая может не соответствовать текущей версии.

sqlite> .dump table_a
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE "table_a" ("id" integer NOT NULL PRIMARY KEY, "time" decimal NOT NULL);
INSERT INTO "table_a" VALUES(1,0.4);
INSERT INTO "table_a" VALUES(2,0.6);
INSERT INTO "table_a" VALUES(3,0.0005);
INSERT INTO "table_a" VALUES(4,0.0006);
INSERT INTO "table_a" VALUES(5,0.0004);
COMMIT;

sqlite> select * from table_a where time < 0.0005;
5|0.0004

sqlite> SELECT id, time, typeof(time) FROM table_a;
1|0.4|real
2|0.6|real
3|0.0005|real
4|0.0006|real
5|0.0004|real
...