Таблица SQL для записи Delphi с использованием BCP
У меня есть сценарий, в котором я должен экспортировать данные около 500000 записей из таблицы SQL для использования в приложении Delphi. Данные должны быть загружены в упакованную запись. Есть ли метод, в котором я могу использовать BCP для записи файла данных, аналогичного записи записей в файл.
На данный момент я загружаю данные, используя этот псевдокод.
// Assign the data file generated from BCP to the TextFile object.
AssignFile(losDataFile, loslFileName);
Reset(losDataFile);
while not EOD(losDataFile) do
begin
// Read from the data file until we encounter the End of File
ReadLn(losDataFile, loslDataString);
// Use the string list comma text to strip the fields
loclTempSlist.CommaText := loslDataString;
// Load the record from the items of the string list.
DummyRec.Name := loclTempSList[0];
DummyRec.Mapped = loclTempSList[1] = 'Y';
end;
Для удобства я перечислил тип Dummy rec ниже
TDummyRec = packed record
Name : string[255];
Mapped : Boolean;
end;
Итак, мой вопрос заключается в том, чтобы вместо экспорта данных в текстовый файл можно было экспортировать данные в двоичный файл, чтобы я мог читать из файла напрямую, используя тип записи?
лайк
loclFileStream := TFileStream.Create('xxxxxx.dat', fmOpenRead or fmShareDenyNone);
while loclFileStream.Position < loclFileStream.Size do
begin
// Read from the binary file
loclFileStream.Read(losDummyData, SizeOf(TDummyRec));
//- -------- Do wat ever i want.
end;
У меня нет большого опыта использования BCP. Пожалуйста, помогите мне с этим.
Спасибо Терминатор...
2 ответа
В вашей записи, string[255]
создаст строку Ansi фиксированного размера (т.е. так называемый shortstring
). Этот тип явно устарел и не должен использоваться в вашем коде.
Это будет ужасная трата пространства, чтобы сохранить его напрямую, используя TFileStream
(даже если это будет работать). Каждая запись будет хранить 256 байтов для каждого имени.
И используя string[255]
(т.е. так называемый shortstring
) сделает скрытое преобразование в строку для большинства доступа к ней. Так что это не самый лучший вариант, ИМХО.
Я советую использовать динамический массив, а затем сериализовать / десериализовать его с нашими классами Open Source. Для вашего хранилища вы можете использовать динамический массив. Работает с Delphi 5 до XE2. И вы сможете использовать string
в записи:
TDummyRec = packed record
Name : string; // native Delphi string (no shortstring)
Mapped : Boolean;
end;
Изменить после комментария ОП:
BCP - это просто инструмент командной строки, предназначенный для экспорта большого количества строк в таблицу SQL. Так что ИМХО BCP не является хорошим кандидатом для ваших целей.
Кажется, вам нужно импортировать много строк из таблицы SQL.
В этом случае:
- С помощью
shortstring
в любом случае будет пустой тратой памяти, так что вы получите быстрее из памяти, чем с использованием хорошегоstring
; - Вы можете попробовать наши классы с открытым исходным кодом, чтобы получить все строки данных одну за другой, а затем заполнить свои записи, используя эти данные: см. SynDB классы - он легче, чем ADO; Затем вы сможете извлекать данные записи по одной, а затем использовать наши функции сериализации записей для создания некоторого двоичного содержимого - или попробовать специальный более быстрый движок, такой как SynBigTable;
- Здесь есть несколько статей об использовании напрямую функции OleDB, используемой BCP из кода Delphi - она написана на французском языке, но вы можете использовать Google для ее перевода и здесь для быстрого массового копирования; полный исходный код включен.
Вы хотите прочитать SQL-таблицу в запись, я понятия не имею, почему вы работаете с архаичным AssignFile.
Вы действительно должны использовать TADOQuery (или подходящий вариант) для вашей базы данных.
Поместите в него разумный SQL-запрос; что-то вроде:
SELECT field1, field2, field3 FROM tablename WHERE .....
Если вы сомневаетесь, вы можете использовать:
SELECT * FROM tablename
Который выберет все поля из таблицы.
Следующий код будет проходить через все записи и все поля, сохранять их в вариантах и сохранять их в FileStream.
function NewFile(Filename: string): TFileStream;
begin
Result:= TFileStream.Create(Filename, fmOpenWrite);
end;
function SaveQueryToFileStream(AFile: TFileStream; AQuery: TADOQuery): boolean;
const
Success = true;
Failure = false;
UniqueFilePrefix = 'MyCustomFileTypeId';
BufSize = 4096;
var
Value: variant;
Writer: TWriter;
FieldCount: integer;
c: integer;
RowCount: integer;
begin
Result:= Success;
try
if not(AQuery.Active) then AQuery.Open
FieldCount:= AQuery.Fields.Count;
Writer:= TWriter.Create(AFile, BufSize);
try
Writer.WriteString(UniqueFilePrefix)
//Write the record info first
Writer.WriteInteger(FieldCount);
//Write the number of rows
RowCount:= AQuery.RecordCount;
WriteInteger(RowCount);
AQuery.First;
while not(AQuery.eof) do begin
for c:= 0 to FieldCount -1 do begin
Value:= AQuery.Fields[c].Value;
Writer.WriteVariant(Value);
end; {for c}
AQuery.Next;
end; {while}
except
Result:= failure;
end;
finally
Writer.Free;
end;
end;