テーブルにレコード追加をするには

解決


tassy  2013-03-01 05:30:00  No: 43981

環境  Windows7 Pro 32bit、Delphi2010
エクセルシート上にあるデータ
(フィールド数はシートにより異なり、多いものは100列位×10万件位)
を取得し、テーブルにインポートしたいのですがレコードを追加する方法が分かりません。

エクセルシートからデータを取得し

ExValues : OleVariant;  
  〜略〜
memo1.Lines.Add(Exvalues[1,1]);

で値が入っているのは確認出来ています。

空のテーブルは既に作成してあり、テーブルに追加するため

Table1.Appendrecord([ココの記述]);

が分かりません。

レコード数(行数)は10万件位あり、レコード単位では処理に時間が掛かると思われるので
レコード単位でなく、他に良い方法があれば教えて下さい。


Mr.XRAY  2013-03-01 05:38:48  No: 43982

テーブルにインポートしたいのですがレコードを追加する方法が分かりません。

データベースによっては,そのような,何というのでしょか,コマンド類
が用意されている場合があります.
使用しているデータベースの取り扱い説明書等を確認してみてはどうでしょうか ?


DEKO  2013-03-01 07:21:00  No: 43983

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


KHE00221  2013-03-01 07:25:38  No: 43984

使い方は

    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

だけど

複数のレコードを書き込む為のものではない


Mr.XRAY  2013-03-01 08:55:59  No: 43985

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 ビットバージョンがインストールされて
いるパスです.これも注意してください.


Mr.XRAY  2013-03-01 08:56:41  No: 43986

>Windows 7 の場合,指定しなければ,32 ビットバージョンがインストールされて
>いるパスです.これも注意してください.

おおっと失礼.Windows 7 32bit でしたね.


Mr.XRAY  2013-03-01 09:11:16  No: 43987

それと,サイトに掲載しているエクセルのサンプルでは,
データの更新ができませんが,ACE を使用すると,更新ができます.
xls, xlsx のどちらも扱えるので便利です.


tassy  2013-03-06 04:19:47  No: 43988

みなさんありがとうございます。
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(今更感がかなりありますが、まだ現役なのです)  への登録です。
よろしくおねがいします。


DEKO  2013-03-06 06:02:54  No: 43989

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


tassy  2013-03-06 17:41:29  No: 43990

うーん私の説明が良くなかったですかね。
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;

でうまく書き込み出来ましたので解決とさせて頂きます。
ありがとうございました。


ありい  2013-03-07 03:42:19  No: 43991

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];

...に変更すれば、お望みの動きになりませんか??


tassy  2013-03-07 18:01:31  No: 43992

なるほど
ありいさんの手順でうまく出来ました。
今までポインタには遭遇せずに過ごせたので..
ポインタはこのような動作になるのですね、もっと勉強します。
ありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加