Ошибка с SQLite (округляет числа в выборке)

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Ответить
tria
постоялец
Сообщения: 401
Зарегистрирован: 03.04.2006 11:24:10
Контактная информация:

Ошибка с SQLite (округляет числа в выборке)

Сообщение tria »

Кусок кода:

Код: Выделить всё

  
var qS: TSQLQuery;
     SQLCon: TSQLite3Connection;
     trn:TSQLTransaction;

  qS.SQL.Add('SELECT A.Tov tovar_id, A.NumStrPrih numstrprih,');
  qS.SQL.Add('       sum(A.Kvo)  kvo  FROM DocsStr A');
  qS.SQL.Add('WHERE IdDoc=110');
  qS.SQL.Add('GROUP BY A.Tov,  A.NumStrPrih, A.Comment');

  qS.Open;

  while not qS.EOF do  begin
    s:='';
    for j := 0 to qs.FieldCount - 1 do begin
      s:=s+qs.Fields[j].FieldName+'='+qs.Fields[j].AsString+'  ';
    end;
    Memo1.Lines.Add(s);
    qS.Next;
  end;

Если в выборке первая запись kvo целое, то во всех остальных записях оно округляется до целого. А не должно!
Если дробное, то результат запроса такой, каким должен быть.
Если в запросе убрать суммирование/группирование, то результат правильный.
Тр..сь второй день...
Аватара пользователя
Снег Север
долгожитель
Сообщения: 3071
Зарегистрирован: 27.11.2007 15:14:47
Контактная информация:

Сообщение Снег Север »

А поле Kvo как определено в базе данных? Как double или integer?

Добавлено спустя 1 час 44 минуты 42 секунды:
В общем проверил у себя. SQLite позволяет без проблем писать дробные числа в поля, определенные как integer. Но для правильной обработки данных в функциях и пр. надо для поля использовать CAST(<имя> AS FLOAT)
tria
постоялец
Сообщения: 401
Зарегистрирован: 03.04.2006 11:24:10
Контактная информация:

Сообщение tria »

Тип поля kvo NUMERIC(12,3)

Извиняюсь, был занят...
Аватара пользователя
Снег Север
долгожитель
Сообщения: 3071
Зарегистрирован: 27.11.2007 15:14:47
Контактная информация:

Сообщение Снег Север »

tria писал(а):Тип поля kvo NUMERIC(12,3)
Извиняюсь, был занят...
всё равно попробуйте sum(CAST(A.Kvo AS FLOAT)) - должно сработать
pupsik
энтузиаст
Сообщения: 1154
Зарегистрирован: 20.08.2014 16:20:13
Контактная информация:

Сообщение pupsik »

Колонка с цифровой (NUMERIC) средство может содержать значения, используя все пять классов хранения. Когда текстовые данные вставляются в числовой столбец, класс хранения текста преобразуется в целое или вещественное (в порядке предпочтения), если такое преобразование без потерь и обратимым. Для преобразования между текстовыми и реальных классов хранения, SQLite считает переход на без потерь и обратимым, если первые 15 значащих десятичных цифры номера сохраняются. Если преобразование без потерь текст, чтобы целого или вещественного невозможно, то значение сохраняется с использованием класса хранения TEXT. Никакая попытка не сделана, чтобы преобразовать NULL или BLOB значения.

Взято из: https://www.sqlite.org/datatype3.html

Если я правильно понимаю в sqilte есть только 3 типа поля:
TEXT as ISO8601 strings ("YYYY-MM-DD HH:MM:SS.SSS").
REAL as Julian day numbers, the number of days since noon in Greenwich on November 24, 4714 B.C. according to the proleptic Gregorian calendar.
INTEGER as Unix Time, the number of seconds since 1970-01-01 00:00:00 UTC.
и то довольно витиевато. Мне особенно понравилось хранение даты. Черт ногу сломит :)
Аватара пользователя
Снег Север
долгожитель
Сообщения: 3071
Зарегистрирован: 27.11.2007 15:14:47
Контактная информация:

Сообщение Снег Север »

sqilte ИМХО даже чрезмерно либерален в сохранении данных всевозможных типов. Для несерверной базы, рассчитанной на работу с единственным приложением, это приемлемо, конечно. Оборотной стороной является перекладывание на программиста работы по правильной интерпретации данных.
tria
постоялец
Сообщения: 401
Зарегистрирован: 03.04.2006 11:24:10
Контактная информация:

Сообщение tria »

Проблема в Лазаре. Тот же самый запрос в SQL админе выдает правильные цифири.
Задание типа поля до/после выполнения запроса тоже ничего не дало.

Код: Выделить всё

  qs.FieldDefs.Add('kvo', ftFloat);
  qs.FieldDefs[2].Precision:=3;
  qs.FieldDefs[2].Size:=13;

  qS.Open;

  qs.FieldDefs[2].DataType:=ftFloat;
  qs.FieldDefs[2].Precision:=3;
  ShowMessage(IntToStr(qs.FieldDefs[2].Precision));
  qs.FieldDefs[2].Size:=13;


Обращение к полю .AsFloat тоже возвращает целое...
Аватара пользователя
Снег Север
долгожитель
Сообщения: 3071
Зарегистрирован: 27.11.2007 15:14:47
Контактная информация:

Сообщение Снег Север »

Изменение поля в лазарусе и не может ничего вам дать. Или измените тип поля в таблице на REAL, или используйте в запросе CAST.
Тип NUMERIC - это, фактически, текстовое поле, вывод из которого преобразуется по загадочным законам кармы :)
Так что следите за результатом сами.
pupsik
энтузиаст
Сообщения: 1154
Зарегистрирован: 20.08.2014 16:20:13
Контактная информация:

Сообщение pupsik »

1.
Если в выборке первая запись kvo целое, то во всех остальных записях оно округляется до целого.

2. Я специально выделил:
(в порядке предпочтения)
.

Т.о. если первое число целое то и остальные будут считаться целым. Дык что странного в этом нет. Все согласно их вики :)

п.с.
Насчет бага в лазаре. Кто его знает что считать багом. То ли то что sqlite так сложен, то ли то что разрабы не сделали "исключение". Попробуйте зеос или мсе...
tria
постоялец
Сообщения: 401
Зарегистрирован: 03.04.2006 11:24:10
Контактная информация:

Сообщение tria »

Помогло приведение к Real:

Код: Выделить всё

 CAST(sum(A.Kvo) as Real)  kvo  FROM DocsStr A

Приведение к Numeric не помогало.
Большое спасибо Снег Север!
Ответить