Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Как узнать тип поля в открытом датасете?


Страницы:   1 2

SergP. ©   (2006-09-12 11:07:00) 

Имеется ввиду если поле типа number(20,4) то как узнать количество знаков и кол. знаков после точки?


MsGuns   (2006-09-14 09:38:00) [1]

Дело в том, что тип данных - штука вообще интересная. Разные сервера хранят те же самые "деньги" по-разному.
Именно поэтому в Дельфи разработчики предусмотрели класс TField, который как бы объединяет в себе возможный спектр представления данных в физическом формате, приводит все разнообразие серверных типов данных к некому множеству-знаменателю. Предоставляя "движкам" или провайдерам собственно преобразование "нативных" форматов серверов к "машинному".
Часто все эти Currency, BCD и и т.д. якобы "числовые" данные сервером обрабатываются и сохраняются именно как float (ну не умеет процессор работать с дес.разрядами !), а при извлечении или сохранении округляет их до указанной значности (для денежки - до 4 дробных знаков, для BCD - как указано в дескрипторах таблицы), создавая таким образом иллюзию дес. числа с фиксированной точкой и вводя в заблуждение новичков.

ИМХО, не стОит самому заниматься детальной разработкой каких-то алгоритмов преобразования чисел. Лучше, чем это делают разработчики серверов, у Вас навряд ли получится.


SergP.   (2006-09-13 18:58:00) [2]

> Я все-таки не понял, почему нельзя решить "проблему" с помощью
> свойства DataType, Precission... самих полей.


Насчет Precission можно поподробнее, а то я этим пока не встречался...


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


Желательно чтобы и такое можно было делать... Но на практике в данной задаче такое не встречается...

Пока написал так (это пока в сыром виде), вроде работает:

procedure CreateDBF(ADOConnect:TADOConnection;sql,filename:string);
 procedure WinToDos(var St: string);  // перекодирование из WIN в DOS
 const
   // Кроме перекодировки нужных символов (укр. буквы) - остальное пока фигня (но оно не особо нужно)
   WtDTable: string = '0123456789abcdef0123456789abcdef01234567'#$f0'9'#$f2'bcde'#$f4'01'#$f6#$f7'4567 '#$f1'9'#$f3'bcde'#$f5;
 var
   ch: integer;
 begin
   for ch:=1 to length(st) do
     if ord(st[ch])>=$C0 then
        if ord(st[ch])<$f0
           then st[ch]:=chr(ord(st[ch]) xor $40)
           else st[ch]:=chr(ord(st[ch]) xor $10)
       else if ord(st[ch])>127 then st[ch]:=WtDTable[ord(st[ch])-127];
  end;
var
 DBFHeader:packed record              // Заголовок DBF-файла
           Version  : byte;           // Версия
           yy,mm,dd : byte;           // Дата модификации
           MaxRecs  : longint;        // Кол-во записей
           HplusD   : word;           // Положение первой записи
           RecLen   : word;           // Длина записи
           Reserv1  : array[12..27] of byte;
           IsIndex  : byte;           // Наличие привязаного CDX - файла
           CodePage : byte;           // Кодовая страница
           Reserv2  : array[30..31] of byte;
           end;
 FieldDesc:array of packed record     // подзаписи полей
           Name:array[1..11] of byte; // Имя поля
           Typ : char;                // Тип поля
           Res1: longint;
           Len : byte;                // Длина поля
           Dec : byte;                // Кол-во десятичных знаков
           Res2: array[1..13] of byte;
           Tag : byte;
           end;
 i,charcount:integer;
 term:byte;
 fldname:string;
 StrFldValue:string;
begin
 with TADODataSet.Create(Application) do
 try
   DisableControls;
   Connection:=ADOConnect;
   CommandText:=sql;
   Open;
   SetLength(FieldDesc,FieldCount);
   DBFHeader.RecLen:=1;    // Длина записи равна сумме длин полей +1 (признак удаления)
   for i:=0 to FieldCount-1 do
   begin
     fldname:=AnsiUpperCase(Fields[i].DisplayName);
     for charcount:=1 to 10 do
       if charcount>length(fldname)
          then FieldDesc[i].Name[charcount]:=0
          else FieldDesc[i].Name[charcount]:=ord(fldname[charcount]);
     FieldDesc[i].Name[11]:=0;
     case Fields[i].DataType of
       ftString:  begin
                    FieldDesc[i].Typ:='C';
                    FieldDesc[i].Len:=Fields[i].Size;
                    FieldDesc[i].dec:=0;
                  end;
       ftInteger: begin
                    FieldDesc[i].Typ:='N';
                    FieldDesc[i].Len:=10;
                    FieldDesc[i].dec:=0;
                  end;
       ftBCD:     begin
                    FieldDesc[i].Typ:='N';
                    FieldDesc[i].Len:=Fields[i].DisplayWidth;
                    FieldDesc[i].dec:=Fields[i].Size;
                  end;
       ftDateTime:begin
                    FieldDesc[i].Typ:='D';
                    FieldDesc[i].Len:=8;
                    FieldDesc[i].dec:=0;
                  end;
     end; //case
     inc(DBFHeader.RecLen,FieldDesc[i].Len);
   end; // for i:=0 to FieldCount-1 do
   DBFHeader.Version:=3;           // Версия DBF-файла (DBASE III/DBASE IV/Foxpro без memo)
   DBFHeader.MaxRecs:=RecordCount; // Кол-во записей
   DBFHeader.IsIndex:=0;           // Индексного файла у нас нет
   DBFHeader.CodePage:=$65;        // Кодовая страница 866
   DBFHeader.HplusD:=SizeOf(FieldDesc[0])*length(FieldDesc)+SizeOf(DBFHeader)+1;
   with TFileStream.Create(filename,fmCreate) do
   try
     WriteBuffer(DBFHeader,SizeOf(DBFHeader));
     WriteBuffer(FieldDesc[0],SizeOf(FieldDesc[0])*length(FieldDesc));
     term:=13;                     // конец заголовков
     WriteBuffer(term,1);
     first;
     while not eof do
     begin
       term:=32;                   // Запись не помеченая на удаление
       WriteBuffer(term,1);
       for i:=0 to High(FieldDesc) do
       begin
         case FieldDesc[i].typ of
           'D': StrFldValue:=FormatDateTime('yyyymmdd',Fields[i].asDateTime);
           'C': begin
                  StrFldValue:=Fields[i].AsString;
                  WinToDos(StrFldValue);
                  while length(StrFldValue)<FieldDesc[i].Len do StrFldValue:=StrFldValue+' ';
                end;
           'N': begin
                  StrFldValue:=FloatToStrF(Fields[i].AsFloat,ffFixed,FieldDesc[i].Len,FieldDesc[i] .Dec);
                  while length(StrFldValue)<FieldDesc[i].Len do StrFldValue:=' '+StrFldValue;
                end;
         end;
         WriteBuffer(pointer(StrFldValue)^,length(StrFldValue));
       end;
       next;
     end;
     term:=26;      // конец файла
     WriteBuffer(term,1);
   finally
     free;
   end;
 finally
   free;
 end;
end;


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


Reindeer Moss Eater   (2006-09-13 17:37:00) [3]

Никакой. TFloatField это плавающая точка.
Фиксированная точка у TBCDField.
Но какое там поле у автора - зависит от движка и параметров его настройки.


MsGuns   (2006-09-13 15:24:00) [4]

>Reindeer Moss Eater ©   (13.09.06 13:32) [34]
>Видимо потому что в случае TFloatField оба эти свойства бесполезны.

Мне непонятно, какой может быть значность дроби в float?


Reindeer Moss Eater   (2006-09-13 13:32:00) [5]

Я все-таки не понял, почему нельзя решить "проблему" с помощью свойства DataType, Precission... самих полей.

Видимо потому что в случае TFloatField оба эти свойства бесполезны.


ANB   (2006-09-13 13:18:00) [6]


> как в исходной, оракловской таблице.

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


MsGuns   (2006-09-13 09:25:00) [7]

Я все-таки не понял, почему нельзя решить "проблему" с помощью свойства DataType, Precission... самих полей.
Т.е. при создании таблицы целевой БД поля создаются в датасете точно такими же как в исходной, оракловской таблице.
Думаю, что интерпретацию данных из одной СУБД в другую. вполне можно "поручить" движкам.


SergP.   (2006-09-12 18:29:00) [8]

Да и как я понял - DisplayWidth показывает правильно длину NUMBER полей, которые в TFields.DataType идут как ftBCD
а для тех Number , для которых TFields.DataType=ftInteger оно показывает 10 (хм. зато теперь понятно почему, насчет DataSize - тоже уже ясно...)


SergP.   (2006-09-12 18:10:00) [9]

Вобщем как я понял, я могу взять TFields.DisplayWidth
Для NUMBER полей размером от 10 и выше - оно показывает правильно общую длину, а то что для мелких полей показывает 10 -по идее не страшно. просто  я завышу размерность поля. Главное чтобы данные влезли...
:-)


SergP.   (2006-09-12 18:02:00) [10]

> эта, в оракле лучше юзать varchar2


там и есть varchar2, просто я неправильно написал на форуме...


ANB   (2006-09-12 17:56:00) [11]


> varchar

эта, в оракле лучше юзать varchar2


SergP.   (2006-09-12 17:48:00) [12]

> [26] SergP.   (12.09.06 17:42)
> > Какую такую фигню показывает?
>
>
> эксперименты показали, что:
> для полей varchar показывает длину+1
> Для numeric показывает общую длину, но не менее 10


Хотя нет. вру...

для полей varchar показывает длину+1
а для numeric показывает... хм... даже не знаю что... Вобщем фигню...

NUMBER (14,0) показывает  34
NUMBER (6,0) показывает  4
NUMBER (4,0) показывает  4

а общую длину, но не менее 10 - это показывает Displaywidth


SergP.   (2006-09-12 17:42:00) [13]

> Какую такую фигню показывает?


эксперименты показали, что:
для полей varchar показывает длину+1
Для numeric показывает общую длину, но не менее 10


Reindeer Moss Eater   (2006-09-12 17:37:00) [14]

Как в том анекдоте:
"Это у твоего папы фигня, а у слона - то что надо"

Какую такую фигню показывает?


SergP.   (2006-09-12 17:29:00) [15]

По крайней мере TFields.size для varchar показывает длину, а для numeric показывает кол-во символов после точки.
Но вот TFields.Datasize показывает вообще какую-то фигню


ANB   (2006-09-12 17:21:00) [16]

Кстати, покопайся - возможно в оракле шлюз есть. во всяком случае он есть для ms sql.


ANB   (2006-09-12 17:21:00) [17]


> SergP.   (12.09.06 17:12) [21]

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


SergP.   (2006-09-12 17:12:00) [18]

> [20] ANB ©   (12.09.06 17:04)
>
> > SergP.   (12.09.06 16:31) [19]
>
> во. есть мысля.
> создаешь на основании своего запроса вьюху, достаешь описания
> полей из user_tab_cols, качаешь из нее данные, грохаешь
> вьюху (чтоб не мешалась).


Хм... мысля конечно реальная, но муторная. Оставлю ее на крайний случай, это если по другому никак не получится.


ANB   (2006-09-12 17:04:00) [19]


> SergP.   (12.09.06 16:31) [19]

во. есть мысля.
создаешь на основании своего запроса вьюху, достаешь описания полей из user_tab_cols, качаешь из нее данные, грохаешь вьюху (чтоб не мешалась).


SergP.   (2006-09-12 16:31:00) [20]

> [18] ANB ©   (12.09.06 16:16)
>
> > SergP.   (12.09.06 16:11) [17]
>
> Весьма приближенно получишь. Тогда уж лучше по словарю лазить.


По словарю - это как?
из sys.user_tab_cols извлекать, что-ли?


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо