|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#1
|
|||
|
|||
Delphi 7 запись таблицы MO Excel в MO Access
Доброго времени суток. Пишу на 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 и имя таблицы - имена колонок и их тип данных - ну и скобочки, хотя это не важно |