![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
#1
|
|||
|
|||
|
Доброго времени суток. Пишу на Delphi 7 прогу для импорта Excel таблиц в базу данных Access. Лазил по форумам с надеждой найти какой нибудь аналог или общее описание, все без успехов. Delphi 7 изучаю не так давно, пару месяцев. Написал код, который загоняет таблицу Excel в массив. Смог вывести это в Memo, но как записать массив со значениями в базу данных Access не пойму. Подключаюсь к базе через компоненты ADO. Код что смог написать руководствуясь разными источниками прилагаю нижу. Сильно не ругайтесь, если неправильно задаю вопрос. Надеюсь на вашу помощь.
Код:
procedure TForm1.BitBtn1Click(Sender: TObject);
var
i, j: Integer;
S: string;
Mass, MRange: Variant;
ExcelApp, Book, Sheet: Variant;
begin
ExcelApp:= CreateOleObject('Excel.Application');
ExcelApp.Visible:= True;
Book:= ExcelApp.Workbooks.Open('D:\Documents and Settings\0\Рабочий стол\ImportExcelBD\Test1\Test1\Книга1.xls');
Sheet:= Book.Sheets[1];
MRange:= Sheet.Range[Sheet.Cells[2,1], Sheet.Cells[7, 3]];
Mass:= MRange.Value;
Memo1.Lines.Add('Прочитаный Массив ячеек:');
for i:= VarArrayLowBound(Mass, 1) to VarArrayHighBound(Mass, 1) do
begin
S:= '';
for j:= VarArrayLowBound(Mass, 2) to VarArrayHighBound(Mass, 2) do
begin
if j > 1 then
S:= S + #9;
S:= S + VarAsType(Mass[i, j], VarOleStr);
end;
Memo1.Lines.Add(S);
end;
end;Последний раз редактировалось Shkolnik_17, 22.12.2018 в 22:28. |
|
#2
|
|||
|
|||
|
Ну если ты до данных ячейки добрался, то в чем проблема?
Код:
for i := VarArrayLowBound(Mass, 1) to VarArrayHighBound(Mass, 1) do begin ADOTable1.Append; ADOTable1.Fields[0].AsString := VarAsType(Mass[i, VarArrayLowBound(Mass, 2)], VarOleStr); ADOTable1.Fields[0].AsString := VarAsType(Mass[i, VarArrayLowBound(Mass, 2)+1], VarOleStr); ADOTable1.Fields[0].AsString := VarAsType(Mass[i, VarArrayLowBound(Mass, 2)+2], VarOleStr); //... сколько у тебя там ячеек... ADOTable1.Post; end; А вообще можно попроще сделать. Тут всавка в MemTable, но это не принципиально, с ADOTable будет работать точно так же. Это собственно чтение из Экселя: Код:
procedure XlsLoad(AFileName : String; ACallBack : TLoadCallBack);
var
ExcelApp : OleVariant;
WrkBook : OleVariant;
I : Integer;
ASheet : String;
ARowFrom, ARowTo : Integer;
RI : TRequirementInfo;
RS : TRequirementSchema;
begin
If @ACallBack = Nil Then Raise Exception.Create('Callback doesn''t set.');
If Not FileExists(AFileName) Then Raise Exception.Create('File doesn''t exist.');
ExcelApp := CreateOleObject('Excel.Application');
Try
WrkBook := ExcelApp.Workbooks.Open(AFileName);
Try
If Not GetSheet(ExcelApp,ASheet,RS) Then Exit;
If Not GetRange(WrkBook, ASheet, ARowFrom, ARowTo)
Then Raise Exception.Create('Can''t find cells range.');
If (ARowTo - ARowFrom) < 1 Then Raise Exception.Create('Cells range is empty.');
For I := ARowFrom To ARowTo Do
Begin
If GetRequirement(WrkBook,ASheet,I,RS,RI)
Then ACallBack(RI);
End;
Finally
WrkBook := NULL;
End;
Finally
ExcelApp.Quit;
ExcelApp := NULL;
End;
end;
function GetRequirement(Book : OleVariant; Sheet : String; Row : Integer; Schema : TRequirementSchema; var RI : TRequirementInfo) : Boolean;
var
Buf : String;
begin
Result := False;
Try
RI.Number := StrToInt(Book.WorkSheets[Sheet].Range['A'+IntToStr(Row)].Text);
RI.ReqName := Book.WorkSheets[Sheet].Range['B'+IntToStr(Row)].Text;
RI.TgtName := Trim(Book.WorkSheets[Sheet].Range['C'+IntToStr(Row)].Text);
Buf := Trim(Book.WorkSheets[Sheet].Range['D'+IntToStr(Row)].Text);
ParseType(Buf,RI.TgtType,RI.TgtTypeLen,RI.TgtTypeLenDec);
RI.SrcName := Trim(Book.WorkSheets[Sheet].Range['I'+IntToStr(Row)].Text);
Buf := Trim(Book.WorkSheets[Sheet].Range['J'+IntToStr(Row)].Text);
ParseType(Buf,RI.SrcType,RI.SrcTypeLen,RI.SrcTypeLenDec);
Buf := Book.WorkSheets[Sheet].Range['K'+IntToStr(Row)].Text;
Buf := Trim(UpperCase(Buf));
RI.Nulls := (Buf = 'YES') Or (Buf = 'Y') Or (Buf = 'NULL');
RI.Normalize := False;
// Fix empty logical name
If Trim(RI.ReqName) = '' Then RI.ReqName := RI.TgtName;
Result := True;
Except
End;
end;Код:
procedure TMainForm.AddRow(RI: TRequirementInfo);
var
Buf : String;
bGo : Boolean;
begin
mdReqs.Append;
Try
// Exclude lines with empty ('', n/a, derived) source field.
Buf := AnsiUpperCase(Trim(RI.SrcName));
bGo := Not((Buf = '') Or (Buf = 'N/A') Or (Buf = 'DERIVED'));
mdReqs.FieldByName('Go').AsBoolean := bGo;
mdReqs.FieldByName('Num').AsInteger := RI.Number;
mdReqs.FieldByName('Name').AsString := RI.ReqName;
mdReqs.FieldByName('TgtName').AsString := RI.TgtName;
mdReqs.FieldByName('TgtType').AsString := RI.TgtType;
mdReqs.FieldByName('TgtTypeLen').AsInteger := RI.TgtTypeLen;
mdReqs.FieldByName('TgtTypeLenDec').AsInteger := RI.TgtTypeLenDec;
mdReqs.FieldByName('SrcName').AsString := RI.SrcName;
mdReqs.FieldByName('SrcType').AsString := RI.SrcType;
mdReqs.FieldByName('SrcTypeLen').AsInteger := RI.SrcTypeLen;
mdReqs.FieldByName('SrcTypeLenDec').AsInteger := RI.SrcTypeLenDec;
mdReqs.FieldByName('Nulls').AsBoolean := RI.Nulls;
mdReqs.FieldByName('Normalize').AsBoolean := RI.Normalize;
mdReqs.FieldByName('ExtValues').AsString := '';
mdReqs.Post
Except
mdReqs.Cancel;
End;
end;Не смотри, что так сложно сделано, там не просто так все, нужно было еще кучу всего проверить и т.д. Пойми принцип работы, тогда можно переписать короче и проще. Последний раз редактировалось lmikle, 23.12.2018 в 02:04. |
|
#3
|
|||
|
|||
|
Цитата:
А если мне не известно количество колонок в Excel, как циклом загнать все значения массива в Access таблицу. В общем хочу получить такой вариант: выбираю файл Excel и считываю все значения из области ячеек, и циклом загоняю их в Access. По поводу второго твоего предложения я пока разбираюсь. |
|
#4
|
|||
|
|||
|
lmikle, Опишу полную картину. Есть некая система опроса счетчиков, она значения показаний выгружает в Excel. Нужно из этого файла Excel считать все значения и загнать в БД Access для хранения. Колонок в Excel всегда по разному, но максимум 30. Что можешь посоветовать? Если не смогу показать шефу результат в понедельник, хана мне.
|
|
#5
|
|||
|
|||
|
Дык, видимо, ты не понимаешь что такое таблица в Access.
Таблица - это заранее заданная структура данных. Т.е. ко-во колонок и их типы заранее определены. В принципе, можно динамически создавать таблицы. Коли ты знаешь кол-во колонок в Excel, то тогда можно сформировать что-то типа: Код:
var
N : Integer;
I : Integer;
S : String;
Nm : String;
begin
N := GetNumberOfColumns; // Получили кол-во колонок из Excel
Nm := GetTableName; // Получили имя для таблицы
S := 'CREATE TABLE ' + Nm + ' (';
For I := 1 To N Do
Begin
S := S + 'Field_'+IntToStr(I)+' VARCHAR(255)';
If I < N Then S := S + ',';
End;
S := S + ')';
ADOQuery.SQL.Text := S;
ADOQuery.ExecSQL; |
|
#6
|
|||
|
|||
|
lmikle, Вот такая ошибка.
2018-12-23_11-53-37.png Код написал по твоему примеру. Код:
procedure TForm1.BitBtn3Click(Sender: TObject);
var
NCol, I: Integer;
NameTab, S: string;
begin
ADOConnection1.ConnectionString:= 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=DB1.mdb;Persist Security Info=False';
ADOConnection1.Connected:= True;
ADOQuery1.Connection:= ADOConnection1;
NCol:= 10; //количество колонок
NameTab:= 'Tabl1'; // название таблицы
S:= 'CREATE TABLE'+NameTab+'(';
for I:= 1 to NCol do
begin
S:= S+'Field_' +IntToStr(I)+'VARCHAR(200)';
if I < NCol then S:= S+ ',';
end;
S:= S+')';
ADOQuery1.SQL.Text:= S;
ADOQuery1.ExecSQL;
end; |
|
#7
|
|||
|
|||
|
В том, что пробелы в строках удалять было не надо.
Выведи получившуюся команду и посмотри. у тебя слились: - ключевое слово TABLE и имя таблицы - имена колонок и их тип данных - ну и скобочки, хотя это не важно |