環境 Windows7 Pro 32bit、Delphi2010
エクセルシート上にあるデータ
(フィールド数はシートにより異なり、多いものは100列位×10万件位)
を取得し、テーブルにインポートしたいのですがレコードを追加する方法が分かりません。
エクセルシートからデータを取得し
ExValues : OleVariant;
〜略〜
memo1.Lines.Add(Exvalues[1,1]);
で値が入っているのは確認出来ています。
空のテーブルは既に作成してあり、テーブルに追加するため
Table1.Appendrecord([ココの記述]);
が分かりません。
レコード数(行数)は10万件位あり、レコード単位では処理に時間が掛かると思われるので
レコード単位でなく、他に良い方法があれば教えて下さい。
テーブルにインポートしたいのですがレコードを追加する方法が分かりません。
データベースによっては,そのような,何というのでしょか,コマンド類
が用意されている場合があります.
使用しているデータベースの取り扱い説明書等を確認してみてはどうでしょうか ?
AppendRecord は DocWiki にコードサンプルがあります。
[AppendRecord のコード例]
http://docwiki.embarcadero.com/CodeExamples/XE3/en/AppendRecord_%28Delphi%29
シートのデータが 10 万件という事は *.xlsx ですか?
データ追加の時間より Excel オブジェクトの操作の方が時間が掛かりそうですね。
Mr.XRAY さんのサンプルを参考に ADO で開いたほうが高速に動作するかもしれません。
[590_ADO でエクセルに読み出し専用で接続]
http://mrxray.on.coocan.jp/Delphi/plSamples/590_ADO_Excel.htm
*.xlsx は Jet では読み込めないので ACE で読み込みます。
(ACE は *.xls / *.xlsx どっちも読めます)
Mr.XRAY さんのサンプルの
"Microsoft.Jet.OLEDB.4.0" を "Microsoft.ACE.OLEDB.12.0"
"Excel 8.0" を "Excel 14.0" に
読み替えるだけで *.xlsx を処理できると思います。
[Microsoft Access データベース エンジン 2010 再頒布可能コンポーネント]
http://www.microsoft.com/ja-jp/download/details.aspx?id=13255
使い方は
Table1.FieldDefs.Add('DATE',ftDateTime);
Table1.FieldDefs.Add('TEXT',ftString,200);
Table1.FieldDefs.Add('Index',ftInteger);
のとき
Buffer: array[0..2] of TVarRec;
S: ShortString;
E: Extended;
I: Integer;
begin
S := 'ABVCCCC';
E := Now;
I := 999;
Buffer[0].VType := vtExtended;
Buffer[0].VExtended := @E;
Buffer[1].VType := vtString;
Buffer[1].VString := @S;
Buffer[2].VType := vtInteger;
Buffer[2].VInteger := I;
Table1.AppendRecord(Buffer);
//
Table1.AppendRecord([10.2,'AAA',10]);
end
だけど
複数のレコードを書き込む為のものではない
DEKO さん,紹介していただいて,すみませ〜ん.
>[590_ADO でエクセルに読み出し専用で接続]
>http://mrxray.on.coocan.jp/Delphi/plSamples/590_ADO_Excel.htm
この一連の ADO サンプルは,まだ Microsoft.ACE.OLEDB.12.0 対応したコードのは,
ないです,MDB の 2007 のはあるんですが,
先日の ML のスレッドで思い出し,チェックしてみたら,オブジェクト・インスペクタの
設定が残っているのがありました.
利用にあたっては,注意してください.
>"Excel 8.0" を "Excel 14.0" に
なんですが,14.0 は Office 10 なので,
それ以前の場合は,12.0 とか 8.0 にしてください.
上のバージョンの Office 関係は,数値が下でも動作するようです.
ADO の エクセル関係のサンプルは,ほとんどすべて,この変更で動作します.
>[Microsoft Access データベース エンジン 2010 再頒布可能コンポーネント]
>http://www.microsoft.com/ja-jp/download/details.aspx?id=13255
のダウンロードは,Windows の ビットバージョンではなく,Office の
ビットバージョンのことです.
Windows 7 の場合,指定しなければ,32 ビットバージョンがインストールされて
いるパスです.これも注意してください.
>Windows 7 の場合,指定しなければ,32 ビットバージョンがインストールされて
>いるパスです.これも注意してください.
おおっと失礼.Windows 7 32bit でしたね.
それと,サイトに掲載しているエクセルのサンプルでは,
データの更新ができませんが,ACE を使用すると,更新ができます.
xls, xlsx のどちらも扱えるので便利です.
みなさんありがとうございます。
KHE00221 さんのサンプルを参考にさせて頂き、レコードの登録は
出来たのですがフィールド数(列数)が一定ではないので以下のような
記述で(例では11列分で固定してあります)登録を行ったのですが
11列目の値のみが全てのフィールドに書き込まれてしまいます。
var
Buffer :array of TVarRec;
fi:integer;
S:Shortstring;
begin
SetLength(Buffer, 11);
for fi := 0 to 10 do
begin
S := varTostr(ExValues[1,fi+1]);
Buffer[fi].VType := vtString;
Buffer[fi].VString := @S;
end;
Table1.Active := True;
Table1.Appendrecord(Buffer);
end;
ちなみに BDE→dbase4(今更感がかなりありますが、まだ現役なのです) への登録です。
よろしくおねがいします。
KHE00221 さんのコードは、
> 複数のレコードを書き込む為のものではない
なのですよ。
> 空のテーブルは既に作成してあり、テーブルに追加するため
だったら、AppendRecord ではなく
Table1.Append;
Table1.FieldByName('フィールド名1').AsString := 値;
Table1.FieldByName('フィールド名2').AsString := 値;
...
Table1.Post;
ってやるのがいいかと思います。
以下は、DATA.XLSX (Excel) と全く同じ構造の DATA.DBF (Paradox) へ
データを登録するコードです (CODE と NAME という2 つのフィールドがあります)。
uses
..., DBTables, ADODB;
procedure TForm1.Button1Click(Sender: TObject);
var
Table: TTable;
ADOT: TADOTable;
ParadoxFile, ExcelFile: string;
ConnnectionParam: TStringList;
begin
ParadoxFile := '.\DATA.DBF';
ExcelFile := '.\DATA.XLSX';
ADOT := TADOTable.Create(nil);
Table := TTable.Create(nil);
try
// Excel(XLSX) の設定
ConnnectionParam := TStringList.Create;
try
ConnnectionParam.Values['Provider' ] := 'Microsoft.ACE.OLEDB.12.0';
ConnnectionParam.Values['Data Source' ] := ExcelFile;
ConnnectionParam.Values['Extended Properties'] := 'Excel 12.0';
ADOT.ConnectionString := StringReplace(ConnnectionParam.Text, #$0D#$0A, ';', [rfReplaceAll]);
finally
ConnnectionParam.Free;
end;
ADOT.TableName := '[Sheet1$]'; // XLSX の Sheet1 をテーブルとみなす
// Paradox の設定
Table.TableName := ParadoxFile;
// オープン
ADOT.Open;
Table.Open;
while not ADOT.Eof do
begin
Table.Append; // 追加モード
Table.FieldByName('CODE').AsInteger := ADOT.FieldByName('CODE').AsInteger;
Table.FieldByName('NAME').AsString := ADOT.FieldByName('NAME').AsString;
Table.Post; // 登録
ADOT.Next;
end;
// クローズ
Table.Close;
ADOT.Close;
finally
Table.Free;
ADOT.Free;
end;
end;
[データセットについて:インデックス (DocWiki)]
http://docwiki.embarcadero.com/RADStudio/ja/%E3%83%87%E3%83%BC%E3%82%BF%E3%82%BB%E3%83%83%E3%83%88%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%EF%BC%9A%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9
うーん私の説明が良くなかったですかね。
1レコードだけ登録サンプルコードのつもりなのですが。
エクセル上のデータ
A 〜 K列
05,123,456,789,abc,def,ghi,jkl,mn,opq,rst
とあり
for文でBufferにA〜K列の値を入れているつもりで
AppendRecord でTable1に書き込みすると
Aフィールド 〜 Kフィールド
rst,rst,rst,rst,rst,rst,rst,rst,rst,rst,rst
というような状況です。
Bufferにうまく格納されていないのか、記述自体おかしいのか。
DEKOさんの
>Table1.Append;
>Table1.FieldByName('フィールド名1').AsString := 値;
>Table1.FieldByName('フィールド名2').AsString := 値;
>...
>Table1.Post;
でうまく書き込み出来ましたので解決とさせて頂きます。
ありがとうございました。
tassyさん、こんばんは。横から失礼します。
11回ループして代入している下記の部分ですが、
> Buffer[fi].VString := @S;
は、S(ShortString)のポインタを代入しているので、最後11回目の値が全てのフィールドに書かれているのだと思います。
宣言を
S: array [0..10] of ShortString;
代入を
S[fi] := varTostr(ExValues[1,fi+1]);
最後のポインタの代入を
Buffer[fi].VString := @S[fi];
...に変更すれば、お望みの動きになりませんか??
なるほど
ありいさんの手順でうまく出来ました。
今までポインタには遭遇せずに過ごせたので..
ポインタはこのような動作になるのですね、もっと勉強します。
ありがとうございました。
ツイート | ![]() |