![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как узнать тип поля в открытом датасете?
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 извлекать, что-ли?