旧Delphi FAQ – データベース

Abstract: このQ&Aは、旧www.borland.co.jp に掲載されていた記事を転載したものです。記事は掲載時点の情報をあるがままに掲載しており、新バージョンでのご利用においては、コンポーネントやAPIの仕様変更等によりご利用いただけない場合がありますのでご留意ください。

    指定した DBGrid の項目の内容を取得する方法?

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
指定した DBGrid の項目の内容を取得するにはどうしますか。

A:
SelectedField プロパティ又は,SelectedIndex プロパティ 等をご使用ください。
例を以下に示します。

(例)マウスでクリックした DBGrid の項目の内容を Edit1 に表示する。

   procedure TForm1.DBGrid1DblClick(Sender: TObject);
   begin
     Edit1.Text := DBGrid1.SelectedField.AsString;
  end;

    「ネットワークファイルのアクセス用に初期化されません」

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
データーベースをアクセスするプログラムを実行した際「ネットワークファイルのアクセス用に初期化されていません」のメッセージダイアログボックスが表示されてしまいます。

A:
Paradox のテーブルを共有するためにネットワークファイルを置くディレクトリを設定しなければなりません。 テーブルを共有するために使用するディレクトリを決め,BDE 環境設定のプログラムを実行してドライバー Paradox の NET DIR に記述してください。

    \delphi\demos\db\animals\animals.dpr を実行すると例外エラー発生

該当するバージョン:Delphi 1.0

Delphi 1.0J のサンプルプログラムの animals.dpr を実行すると,「プロジェクトANIMALS.EXE が EDatabeseError クラスの例外を生成しました。・・・・」 を表示します。
データーベースアプリケーションは SHARE.EXE が実行されていなければ正しく動作しません。必ず SHARE.EXE をロードするようにしてください。
AUTOECEC.BAT に SHARE /F:4096 /L:400 を追加してください。

    Delphi で Paradox 形式のテーブルにプライマリインデックスを設定

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Paradox 形式のテーブルに対してプライマリインデックス(複数フィールド)を設定する場合は,ローカル SQL の CREATE TABLE を使用します。

例 3つの項目(項目名が FLD1,FLD2,FLD3)を含む Paradox 形式のデータベースを作成し,FLD1,FLD2 をプライマリキーに設定します。

   CREATE TABLE "TEST.DB"
   (
      FLD1 SMALLINT,
      FLD2 CHAR(15),
      FLD3 CHAR(30),
      PRIMARY KEY(FLD1,FLD2)
   )

なおプライマリインデックスはテーブル作成時にのみ登録可能です。
CREATE INDEX ではセカンダリインデックスのみ設定できます。

    フォームの実行時にエラー。"データセットは閉じています"

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

計算項目のある TTable へのアクセス,フォームの実行時にエラー

OnCalcField イベントハンドラが指定されている TTable オブジェクトの Active プロパティが TRUE に設定されている場合,フォームの OnCreate よりも先にOnCalcField イベントハンドラが呼び出されます(Active プロパティが False の場合は OnCreate より先に Oncalc が呼び出される事はありません)。 このため,フォームの実行時に"データセットは閉じています。"等のエラーが発生します。
計算項目を持つ TTable を取り扱う場合は,Acvive プロパティは False に設定し,OnCreate のイベントハンドラで Active := TRUE を指定するようにしてください。

    二つのテーブルをリンクして一つの DBGrid に表示したい

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
複数のテーブルをリンクして必要な項目だけを一つの DBGrid に表示したい。

A:
SQL により複数テーブルの検索結果を DBGrid に反映させることは可能です。
たとえば,次のような二つのテーブルの field_A,field_B,field_D を一つの DBGrid に表示するには,以下のような SQL 文を TQuery に記述します。

   Tbl1.db:  field_A        Tbl2.db:  field_C
             field_B                  field_D
             field_C

   SELECT Tbl1."field_A", Tbl1."field_B", Tbl2."field_D" 
   FROM Tbl1, Tbl2
   WHERE Tbl1."field_C" = Tbl2."field_C"

    テーブルを編集するには

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
テーブル編集用のコードを書きました。始めの1件は処理しますが,2件めでメッセージがでてエラーになります。どのように修正したらよいのでしょうか?

   procedure Tupd.Button1Click(Sender: TObject);
   begin
     table1.open;
     table1.edit;
     while not table1.EOF do
     begin
       table1Name.value := 'TEST-TEST-TEST';
       table1.next;
     end;
     table1.close;
   end;

A:
レコードは,Edit で編集状態にした後 Post を発行することで更新がテーブルに登録されます。この時点で編集状態を終了します。
Post を明示しない場合でも,編集状態で Next を実行することで自動的に Post が実行され,編集状態を終了します。
Table1.Edit を Table1Name.Value := ... の直前に移動させると各レコードを変更できます。

    CanModify プロパティが True でもテーブルが更新できません

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
テーブルを更新する際に,Table の CanModify プロパティを確認してテーブルを更新しようとしても例外が発生します。また,table1.next のように,Post を発行し編集状態を終了するような処理を実行した後でも True です。このプロパティは実際は何を表わしているのでしょうか?

A:
CanModify プロパティは,アプリケーションがデータセット内のデータを変更できるかどうかを指定します。このプロパティが False の場合,データセットは読み出し専用となり,Edit 状態や Insert 状態に移行できません。CanModify がTrue の場合は Edit や Insert を発行することで編集状態に移行できます。
また,Table の ReadOnly プロパティを True にすると,CanModify は False になり Edit や Insert など,テーブルを更新するメソッドを使用すると例外が発生します。

    参照の整合性

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
Delphi で Paradox テーブルを扱った時,Paradox/winで参照の整合性を設定してある場合,Paradox/win で使用しているのと同じ様に扱えるのでしょうか。
例えば,Paradox/win では参照の整合性を設定してあれば,マスターテーブルの値を変更すると子テーブルの値は変更されたマスターテーブルの値に従って変更されますが,Delphiでも同じ様にできるのでしょうか?

A:
残念ながら,Delphi のコンポーネントベースの開発では,Paradox のような参照の整合性を処理することはできません。

    複数テーブルのインデックスが一致するレコードの検索

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
顧客テーブルと受注テーブルの顧客番号が一致するものを検索したいのですが。

A:
以下のコードを参考にしてください。

   procedure TForm1.Button1Click(Sender: TObject);
   begin
     with Query1 do begin
       Close;
       with SQL do begin
         Clear;
         Add('SELECT 顧客.顧客番号, 顧客.顧客名, 受注.受注日');
         Add(' FROM 顧客, 受注 WHERE 顧客.顧客番号 = 受注.顧客番号');
       end;
       Open;
     end;
   end;

    1レコード分のデータを Edit コンポーネントに表示

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
SQL を発行した結果の1レコード分のデータを Edit コンポーネントに表示するにはどうしますか?

A:
以下のように行えますのでお試しください。

   procedure TForm1.Button1Click(Sender: TObject);
   var
     wname: string;
   begin
     wname := Edit1.text;
     with Query1 do begin
       Close;
       with SQL do begin
         Clear;
         Add('SELECT * FROM "ANIMALS.DBF" WHERE NAME = "' + wname + '"');
       end;
       Open;
       { 1 レコード分を Edit コンポーネントに 表示  }
       EDIT2.TEXT := FieldByName('NAME').AsString + ' ' +
                     FieldByName('SIZE').AsString + ' ' +
                     FieldByName('WEIGHT').AsString + ' ' +
                     FieldByName('AREA').AsString;
     end;
   end;

    複合キーを使用して dBase のテーブルに検索を行うには

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
複合キーを使用して dBase のテーブルに検索を行いたいのですが。

A:
以下のようにできます。 なお,TTable.IndexName には,dBase の Index On コマンドで作成した Tag 名を指定します。

   procedure TForm1.Button1Click(Sender: TObject);
   begin
    with Table1 do
    begin
      SetKey;
      FieldByName('NUM').AsString := Edit1.text;
      FieldByName('A').AsString := Edit2.text;
      GotoKey;
      Label1.caption := FieldByName('A').Value;
    end;
   end;

    DisplayLabelを変更するには

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
DBGrid に表示される項目名(DisplayLabel)を変更するにはどうしますか?

A:
以下のようなコードで,DisplayLabel を変更することが可能です。

   procedure TForm1.Button1Click(Sender: TObject);
   begin
     DataSource1.DataSet := Query1;
     with Query1 do begin
       Close;
       DatabaseName := 'DBDEMOS';
       with SQL do begin
         Clear;
         Add('SELECT * FROM country.db');
       end;
       Active := True;
       Open;
       Fields[2].DisplayLabel := '大 陸';  { 項目名は '大 陸' と表示されます }
     end;
   end;

    日付項目の区切り文字を変更するには

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
フォームに配置したグリッドにデータを表示する際に,日付項目の区切り文字が '/' となります。 '.' を使用したいのですが。

A:
DBGrid に日付項目を表示されるときに,区切り文字として '.' を指定されたい場合には以下のように行えます。

  1. Table1 コンポーネントをダブルクリックして, Form1.Table1 の項目の編集から,日付項目を追加します。
  2. オブジェクトインスペクタから,日付項目を選択して,その DisplayFormat プロパティに,'yyyy.mm.dd' と入力してください。

    Delphi 1.0 で DbiDeleteAlias が使用できない

該当するバージョン:Delphi 1.0

Q:
Delphi 1.0 で DbiDeleteAlias が使用できません。

A:
Delphi 1.0J で DbiDeleteAlias が使用できません。
次のようなユニットを作成し,アプリケーション側で uses してご使用ください。

   unit DbiProc2;

   interface

   uses
     DbiProcs, DbiTypes;

   function DbiDeleteAlias (               { Delete an alias }
         hCfg          : hDBICfg;          { Config Handle/NULL }
         pszAliasName  : PChar             { Alias name }
      ): DBIResult;

   implementation

   function DbiDeleteAlias; external 'IDAPI01';

   end.

    プログラムで,DBGrid の特定のセルを指定する方法

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
プログラムで,DBGrid の特定のセルを指定するにはどうしますか?

A:
プログラムで,DBGrid の特定のセルを指定するには次のようにするとよいでしょう。
テーブルの最初のレコードから Edit1 で指定されたレコード数だけ移動して,Edit2 で指定された項目の位置にフォーカスを設定します。

   procedure TForm1.Button1Click(Sender: TObject);
   begin
     Table1.First;
     Table1.Moveby(StrToInt(Edit1.Text)-1);
     DBGrid1.SelectedIndex := StrToInt(Edit2.Text) - 1;
     DBGrid1.SetFocus;
   end;

    二番目以降のインデックスへの範囲指定が有効にならない

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
SetRange で複数の項目の範囲を指定していますが,二番目以降の範囲指定が有効にならないのですが。

A:
SetRange や SetRangeStart 及び SetRangeEnd はレコードのポイント(初めと終り) を指定するものです。たとえば次のようなテーブルがあるとします。

このような場合 SetRange( [1,1], [3, 2] ); とすると A から B までのレコード全てをデータとして扱うことになります。 C のレコードを省く事は行ないません。

    TQuery で 255文字を越える SQL 文の使い方

該当するバージョン:Delphi 1.0

Q:
Delphi の TQuery で 255文字を越える SQL 文を使いたいのですがどうすればよいでしょうか?

A:
Add メソッドで SQL 文を指定する時に,適当な長さで分割し ADD してください。
ただし,コマンドの途中や項目の途中で分割することはできません。

   Query1.SQL.ADD('SELECT * FROM TABLE1 ') ;
   Query1.SQL.ADD('WHERE CUST_NO=123') ;
   Query1.Open ;

    TQueryで Insertできない

Q:
TQuery.Insertを実行すると「書き込み禁止のデータは変更できません」のエラーが発生して登録できないのはどうしてでしょうか?

A:
TQueryの RequestLiveプロパティの値を確認してください。RequestLiveの値が Falseの場合、SELECT問い合わせで取得した結果セットは、常に読み出し専用となり、TQuery.Insert等の更新の実行を行うことはできまません。

更新可能な結果セットを要求する場合は、RequestLiveの値を Trueとしてください。ただし、RequestLiveの値を Trueにしても、必ずしも更新可能な結果セットが返却されるわけではありません。データベースが更新可能な結果セットを返すことができない場合は読み出し専用の結果セットが返されます。更新可能な結果セットが返却されたかどうかは、CanModifyプロパティの値を参照してください。

    異種間の問い合わせの作成の具体的方法

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
異種間の問い合わせの作成」は,具体的にはどのようにすればよいのでしょうか?

A:
以下に,別々のサーバー上にある2つのテーブルを結合する場合を示します。
まず,フォーム上に,TDatabase を2つ,TDatasource と TQuery をそれぞれ1つ貼り付けます。 つぎに,TDatabase の AliasName に問い合わせを行うエリアスを設定します。

   Database1.AliasName := 'Alias1' ;
   Database1.DatabaseName := 'DB1' ;
   Database2.AliasName := 'Alias2' ;
   Database2.DatabaseName := 'DB2' ;
   Database1.Open ;
   Database2.Open ;
   Datasource1.DataSet := Query1 ;

最後に SQL 文を作成し,発行します。

   Query1.Close ;
   Query1.SQL.Clear ;
   Query1.SQL.Add('Select *' +
          'From '':db1:orders.db'' a, '':db2:customer.db'' b ' +
          'Where a.CustNo=b.CustNo') ;
   Query1.Open ;

    Query SQL文での日付型の指定

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
Query の SQL文の WHERE で項目の条件を指定する時,日付型はどのように指定すればよいのでしょうか。

A:
日付型の項目は " " でくくります。

   procedure TForm1.Button1Click(Sender: TObject);
   begin
     DataSource1.DataSet := Query1;
     DBGrid1.DataSource :=DataSource1;
     with Query1 do begin
       Close;
       DatabaseName := 'PdoxSample';
       with SQL do begin
         Clear;
         Add(' SELECT DISTINCT 注文番号, 顧客番号, 受注日, 発送日, 輸送方法 ');
         Add(' FROM "受注.DB"');
         Add(' WHERE (受注日 > "05/01/1988")  AND (受注日 < "06/01/1988")');
         Add(' ORDER BY 注文番号, 顧客番号, 受注日, 発送日, 輸送方法');
        end;
       Active := True;
       Open;
     end;
   end;

    ORACLE のエラーメッセージの表示

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
Delphi で ORACLE のエラーメッセージを表示するには,どのようにすればよいですか。

A:
ORACLE のエラーメッセージは例外処理で表示することができます。

   try
     :
     :
   except
     on E: Exception do
     begin
       MessageDlg(E.Message, mtError, [mbOk], 0);
     end;
   end;

    ORACLE の自動コミット

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
Delphi からパススルーSQLで ORACLE にテータ定義(CREATE TABLE)を行うと,自動的にコミットされてしまうのですが何故ですか。 但しデータ操作(INSERTなど)は自動的にコミットされません。
SQLPASSTHRU MODE は SHARED NOAUTOCOMMIT にしています。

A:
ORACLE 側の設定が,データ定義文を自動的にコミットするようになっている可能性があります。 確認してください。

    SUM 関数の結果の取り込み方

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
Query の SQL 文で,SUM 関数を複数使用した SELECT を行った時 SUM で求めた値(複数)をどのように取り込めばよいのでしょうか。

A:
Delphi では,フィールド名として,SUM,SUM_1,SUM_2 という名前で SUM() の結果を取れるので,FieldByName を用いて行ってください。

   procedure TForm1.Button1Click(Sender: TObject);
   begin
     Query1.Close;
     Query1.SQL.Clear;
     Query1.SQL.Add('select sum(QTY_ORDERED),sum(TOTAL_VALUE),'
                  + 'sum(DISCOUNT) from sales');
     Query1.Open;
     Edit1.Text := Query1.FieldByName('SUM').AsString;
     Edit2.Text := Query1.FieldByName('SUM_1').AsString;
     Edit3.Text := Query1.FieldByName('SUM_2').AsString;
   end;

    TDBGrid からの Drag&Drop を行なうには

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
TDBGrid 上に表示されているデータを TEdit に Drag&Drop したいのですが,どのようにしたらよいでしょうか?

A:
TDBGrid から TMyDBGrid を派生させ,WMLButtonDown メンバを次のように実装します。下記コードを参考にして下さい。TMyDBGrid コンポーネントに表示されているデータを TEdit コンポーネント上に Drag&Drop することによって表示することができます。

   unit Drag1;

   interface

   uses
     SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
     Forms, Dialogs, StdCtrls, DB, DBTables, Grids, DBGrids;

   type
     TMyDBGrid = class(TDBGrid)
     private
       procedure WMLButton(var message: TMessage); message WM_LButtonDown;
     end;
     TForm1 = class(TForm)
       Table1: TTable;
       DataSource1: TDataSource;
       Edit1: TEdit;
       procedure FormCreate(Sender: TObject);
       procedure Edit1DragOver(Sender, Source: TObject; X, Y: Integer;
         State: TDragState; var Accept: Boolean);
       procedure Edit1DragDrop(Sender, Source: TObject; X, Y: Integer);
     private
       { Private 宣言 }
     public
       { Public 宣言 }
     end;

   var
     Form1: TForm1;

   implementation

   {$R *.DFM}

   procedure TMyDBGrid.WMLButton(var message: TMessage);
   begin
     inherited;
     BeginDrag(false);
   end;

   procedure TForm1.FormCreate(Sender: TObject);
   var
     grid: TMyDBGrid;
   begin
     grid := TMyDBGrid.Create(self);
     with grid do begin
       parent := Form1;
       Top := 50;
       left := 20;
       Height := 300;
       Width := 600;
       DataSource :=  DataSource1;
     end;
   end;

   procedure TForm1.Edit1DragOver(Sender, Source: TObject; X, Y: Integer;
     State: TDragState; var Accept: Boolean);
   begin
     Accept := true;
   end;

   procedure TForm1.Edit1DragDrop(Sender, Source: TObject; X, Y: Integer);
   begin
     Edit1.Text := (Source as TDBGrid).SelectedField.AsString;
   end;

   end.

    ASCII ファイルを Delphi がサポートするデータベース形式に変換する方法

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

ASCII ファイルを Delphi がサポートするデータベース形式に変換する方法です。
最小限必要な手順をお知らせします。

  1. フォームに,以下のコンポーネントを配置します。
TTable         2個
TBatchMove     1個
TButton        1個
  1. Table1 のプロパティを以下のように設定します。
DatabaseName   <- エリアスまたは,パスを指定
Name           <- Table1
TableName      <- CUSTOMER.TXT
TableType      <- ttASCII
  1. Table2 のプロパティを以下のように設定します。
DatabaseName   <- エリアスまたは,パスを指定
Name           <- Table2
TableName      <- CUSTOMER  (任意のテーブル名を指定します)
TableType      <- ttParadox
  1. BatchMove1 のプロパティを以下のように設定します。
Destination    <- Table2
Mode           <- batCopy   (batCopy では,テーブルは新規作成されます)
Source         <- Table1
  1. Button1 の OnClick イベントに以下のように記述します。
batchMove1.Execute;

以上の設定後,フォームを実行して Button1 をクリックして CUSTOMER.DB を作成するためには,前以て,ASCII ファイルは勿論ですが,スキーマファイルを用意する必要があります。
Ver 1.0J では,\DELPHI\DOC\ASCIIDRV.TXT に,CUSTOMER.SCH の例とCUSTOMER.TXT の例があります。ASCIIDRV.TXT から CUSTOMER.SCH とCUSTOMER.TXT を流用作成して,フォームの存在するディレクトリに入れてからフォームを実行してください。

    ODBC ドライバー経由により、dBase のテーブルにアクセス

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

32 ビットODBC ドライバーを設定して dBase のデータにアクセスした際に, 「データベースへのログインプロンプト」の表示を抑制する方法をお知らせします。

  1. コントロールパネルから 32ビットODBC を起動すると,「データソース」ウィンドウが現れます。
  2. [追加(A)]を押して,セットアップする ODBC ドライバを指定して[OK]を押します。 dBase へアクセスされる場合には,Microsoft Access dBase Driver(*.mdb) を指定します。
  3. 「データソース」ウィンドウに戻って,[設定(S)]を押すと,「ODBC dBase セットアップ」ウィンドウで,[データソース名],[説明(D)],データベースの[バージョン]を指定します。
    [ディレクトリの選択]を押して,データベースの存在するディレクトリを指定します。
  4. [ディレクトリの選択]後,「ODBC dBase セットアップ」ウィンドウで,[OK],「データソース」ウィンドウで,[閉じる(C)]を押します。
  5. Delphi2.0 の BDE 環境設定を起動して,[新規 ODBC ドライバ]を押します。
  6. [デフォルト ODBC ドライバ(D)]の右下矢印から,[Microsoft dBase Driver]を選択後,[BDE ドライバ名(S)]に任意の名前を指定してください。
    これで,BDE 環境設定を終了します。
  7. フォームに,TTable,TDataSource,TDatabase,TDBGrid を配置します。
  8. TDatabase をクリックして,[ドライバ名]の右下矢印を押して,BDE 環境設定で指定した BDE ドライバー名を選択します。
    [名前(N)]には,任意のローカルエリアスの名前を入力します。
    オプションの,[ログインプロンプトを出す(L)]をチェックを外します。
    [OK]を押します。
  9. TdataSource の DataSet には,Table1 を指定し,TDbGrid の DataSource には,DataSource1 を指定します。
  10. TTable の DatabaseName には,Tdatabse の [名前(N)]で入力したエリアス名を指定します。TableName にテーブル名を指定,Avtive を True にすると,データが TDBGrid に表示されます。

以上です。

    Delphi 2.0J から、dBase IV 2.0J で作った *.DBF が文字化け

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Delphi 2.0J から、dBase IV 2.0J で作った *.DBF を、 DBGrid で表示すると,データの内容(全角)が文字化けします。

これは、dBase IV 2.0J の内部バージョンに依存します。

内部バージョンが

    Z123
    Z170
    Z184

の場合には、文字が化けます。
Z360 (最新)であれば文字化けはありません。

    テーブルの項目の表示方法を指定するには

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
テーブルの項目の表示方法を指定するには,どうすればよいでしょうか?

A:
まず,項目エディタを使って Table コンポーネントに項目(TxxxField)し,それぞれの項目に対して DisplayFomat や EditFormat プロパティを設定します。

    TQuery を使用して,動的に Table を作成するには

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
TQuery を使用して,動的に Table を作成したいのですが,どのようにしたらよいのでしょうか?

A:
TQuery の SQL 文を作成します。コード上で SQL 文の実行を行います。
SQL 文に関しては,下記コードを参考にして下さい。

    CREATE TABLE "employee.db"
    (
      LAST_NAME CHAR(20),
      FIRST_NAME CHAR(15),
      SALARY NUMERIC(10,2),
      DEPT_NO SMALLINT,
      PRIMARY KEY(LAST_NAME, FIRST_NAME)
    )

SQL 文の実行に関しては下記コードを発行して下さい。

    Query1.ExecSQL;

    TQuery で LIKE 演算子を使用して問い合わせを行うには

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
TQuery で LIKE 演算子を使用して問い合わせを行いたいのですが,どのようにするとよいのでしょうか?

A:
TQuery の SQL プロパティで文字列リストエディタで指定します。下記コードを参考にして下さい。

文字列の先頭が'カ'で始まるレコードを抽出します。

    SELECT * FROM
    MyTable m
    WHERE m.'カタカナ' LIKE 'カ%'

    TComboBox にテーブルの項目を表示させるには

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
TComboBox にテーブルの項目を表示させたいのですが,どのようにするとよいのでしょうか?

A:
下記コードを参照して下さい。

'Capital' 項目を,ComboBox1 に表示します。

   procedure TForm1.Button1Click(Sender: TObject);
   var
     rec: LongInt;
     s: string;
   begin
     Table1.open;
     with Table1 do
       begin
         for rec := 0 to RecordCount -1 do
         begin
           s := FieldByname('Capital').AsString;
           if ComboBox1.Items.IndexOf( s ) = -1 then
             ComboBox1.Items.Add( s );
           next;
          end;
       end;
     ComboBox1.ItemIndex := 0;
     Table1.Close;
   end;

    SetKey と GotoKey の使用例

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
データベーステーブル内の値を検索したいのですが,どのようにすればよいのでしょうか?

A:
下記コードを参考にして下さい。
下記コードは,Edit コンポーネントに検索したい値を入力します。

   procedure TForm1.Button1Click(Sender: TObject);
   {  Index は,dBASE 5.1J で作成
      INDEX ON STR(ID,4) + NAME + CITY  TAG NEWINDEX
   }
   begin
     with table1 do
       begin
         SetKey;
            FieldByName('ID').AsString  := Edit1.Text;

            FieldByName('NAME').AsString := Edit2.Text;
            FieldByName('CITY').AsString := Edit3.Text;
        if Gotokey then
            Label1.Caption := 'True'
        else
            Label1.Caption := 'False';
        end;
   end;

    一定の時間間隔で,テーブルを反映させるには

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
テーブルが変更されていることを考慮して,ある一定の時間間隔で,変更されているテーブルを反映させたいのですがどのようにするとよいのでしょうか?

A:
下記コードを参考にして下さい。
テーブルの State プロパティがブラウズ状態であるなら,リフレッシュを行います。

   procedure TForm1.Timer1Timer(Sender: TObject);
   begin
     if Table1.State = dsBrowse then
       Table1.Refresh;
   end;

    マウスでクリックした TDBGrid のセルの値を取得するには

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
マウスでクリックした TDBGrid のセルの値を取得するには,どうしますか?

A:
以下のコードを参照してください。
DBGrid1DrawDataCellを使用してデータを取得できます。

   procedure TForm1.Button1Click(Sender: TObject);
   var
     i :integer;
   begin
     with DBGrid1 do
       Edit1.text := Fields[SelectedIndex].AsString ;
   end;

   procedure TForm1.DBGrid1DrawDataCell(Sender: TObject; const Rect: 
     TRect; Field: TField; State: TGridDrawState);
   begin
     if gdFocused in state then
       with DBGrid1 do
         Edit2.text := Fields[SelectedIndex].AsString ;
   end;

    テーブルにフィルタをかけるには,どうしますか?

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
テーブルにフィルタをかけるには,どうしますか?

A:
以下のコードを参照してください。

   procedure TForm1.Button1Click(Sender: TObject);
   begin
     { 都道府県が東京都をフィルタ }
     Table1.Filter := '[都道府県] = ''東京都''' ;
     Table1.Filtered := true ;
   end;

   procedure TForm1.Button2Click(Sender: TObject);
   begin
     { 顧客番号が 1500 以下(1500 を含む)をフィルタ }
     Table1.Filter := '[顧客番号] <= 1500' ;  
     Table1.Filtered := true ;
   end;

   procedure TForm1.Button3Click(Sender: TObject);
   begin
     { Edit1 に入力された文字列がフィルタの条件 }
     Table1.Filter := '[都道府県] = '''+ Edit1.Text + '''';
     Table1.Filtered := true ;
   end;

   procedure TForm1.Button3Click(Sender: TObject);
   begin
      Table1.Filtered := False: { フィルタ解除 }
   end;

    PickList の使用例

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
テーブルの任意の項目のデータを,DBGrid に表示されている他のテーブルのピックリストとして表示されるには,どうしますか?

A:
以下のコードを参照してください。
Table2 の Company 項目のデータを DBGrid の2番目の項目にピックリストとして表示します。

   procedure TForm1.DBGrid1Enter(Sender: TObject);
   var
     i: Integer;
   begin
     DBGrid1.Columns.Items[1].PickList.Clear;
     Table2.First;
     for i := 1 to Table2.Recordcount do
     begin
       DBGrid1.Columns.Items[1].PickList.Add(
            Table2.FieldByname('Company').AsString);
       Table2.Next;
     end;
   end;

Memo 内のデータをピックリストとして使用するには,Assign を使用します。

   DBGrid1.Columns.Items[1].PickList.Assign(Memo1.Lines);

    バッファをディスクに書き込むには

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
テーブルに対して行われた変更を,ディスクに書き込むにはどうしたら良いですか?

A:
テーブルに対して行われた変更は,テーブルがクローズされるまではディスクに書き込まれません。以下の関数を使用することで,ディスクに書き込むことができます。

DbiSaveChanges(hDBICur);

DbiSaveChanges は,hDBICur に関連付けられたテーブルのバッファのすべての更新内容をディスクに書き込みます。この関数は,いつでも使用できます。
なおこれは,SQL テーブルに対しては,使用できません。

      procedure TForm1.Button1Click(Sender; TObject);
      begin
         DbiSaveChanges(Table1.handle);
      end;

    テーブルに対して,検索するにはどうしますか?

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
テーブルに対して,検索するにはどうしますか?

A:
以下のように,Locate メソッドを使用することができます。
CustNo が 1384.0 かつ EmpNo が 45 のレコードに移動します。
Locate メソッドは指定した検索条件に一致する最初のレコードを見つけ,そのレコードまで移動します。

    procedure TForm1.Button1Click(Sender: TObject);
    var
      v: Variant;
    begin
      v := VarArrayCreate([0, 1], VarVariant); {バリアント配列}
      v[0] := 1384.0;
      v[1] := 45;
      Table1.Locate('CustNo;EmpNo', v, [loCaseInsensitive] );
    end;

    テーブルのある項目に同じデータが何レコード存在するか調べるには

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
テーブルのある項目に同じデータが何レコード存在するか調べるには,どうしますか?

A:
COUNT 演算子を使用して HOLDINGS.DBF の SYMBOL 項目に SMC が存在するレコード件数を返します。

   procedure TForm1.Button1Click(Sender: TObject);
   begin
     DataSource1.DataSet := Query1;
     DBGrid1.DataSource :=DataSource1;
     with Query1 do begin
       Close;
       DatabaseName := 'DBDEMOS';
       with SQL do begin
         Clear;
         Add('SELECT COUNT(*) FROM "HOLDINGS.DBF" WHERE SYMBOL = ''SMC''');
       end;
       Open;
     end;
   end;

    Paradox 7.0J をアンインストールすると,BDE が使用できない。

該当するバージョン:Delphi 2.0

Delphi 2.0J と Paradox 7.0J が共存する環境で,Paradox 7.0J をアンインストールすると,Borland Database Engine32 が使用できなくなります。再度,Delphi 2.0J をインストールして Borland Database Engine32 の環境を再設定してください。

    テーブルの項目についての情報を取得するには,どうしたら良いですか?

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
テーブルの項目についての情報を取得するには,どうしますか?

A:
TTable,TQuery,TStoredProc の GetFieldNames メソッドを使用してテーブルの項目名を取得することができます。
TTable,TQuery,TStoredProc の FieldDefs プロパティを使用するともう少し詳しい情報を取得することができます。

   procedure TForm1.Button1Click(Sender: TObject); 
   begin
     ListBox1.Clear;
     Table1.GetFieldNames(ListBox1.Items);  { データセットの各項目の名前を追加 }
   end; 

   procedure TForm1.Button2Click(Sender: TObject);
   var
     i: Integer;
     F: TFieldDef;
     D: String;
   begin
     Table1.Active := True;
     ListBox1.Items.Clear;
     with Table1 do begin
        { FieldDefs プロパティにはデータセット内の各 TFieldDef についての情報
          が入いる。}
       for i := 0 to FieldDefs.Count - 1 do begin  
         F := FieldDefs.Items[i];                            
         case F.DataType of    {  項目型の判断 }
           ftUnknown: D := 'Unknown';
           ftString: D := 'String';
           ftSmallint: D := 'SmallInt';
           ftInteger: D := 'Integer';
           ftWord: D := 'Word';
           ftBoolean: D := 'Boolean';
           ftFloat: D := 'Float';
           ftCurrency: D := 'Currency';
           ftBCD: D := 'BCD';
           ftDate: D := 'Date';
           ftTime: D := 'Time';
           ftDateTime: D := 'DateTime';
           ftBytes: D := 'Bytes';
           ftVarBytes: D := '';
           ftBlob: D := 'BLOB';
           ftMemo: D := 'Memo';
           ftGraphic: D := 'Graphic';
         else
           D := '';
         end;
         {  項目名,項目型,項目幅の表示 }
         ListBox1.Items.Add(F.Name + ', ' + D + ':' + IntToStr(F.Size));
       end;
     end;
     Table1.Active := False;
   end;

    Query のメモ項目を文字列として取得するには,どうしますか?

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
Query のメモ項目を文字列として取得するには,どうしますか?

A:

  1. フォームに TQuery コンポーネント(Query1)を配置します。

DataBaseMame プロパティを DBDEMOS に設定
SQL プロパティを Select * from Biolife に設定
Active プロパティを True に設定

  1. フォームに TEdit コンポーネント(Edit1)を配置します。
  2. フォームに TButton コンポーネント(Button1)を配置します。
  3. Query1 をダブルクリックし,メモ項目を追加します。
    (Biolife.db の Notes 項目を使用)
  4. 以下のコードを, Button1 の OnClick イベントに記述します。
   procedure TForm1.Button1Click(Sender: TObject);
   var
     bs : TBlobStream;
     p  : array [0..50] of char;
   begin
     FillChar(p, SizeOf(p), #0);
     bs:= TBlobStream.Create(Query1Notes, bmRead);
     try
       bs.Read(p,50);
     finally
       bs.Free;
     end;
     Edit1.Text:=StrPas(p);
   end;

    ビットマップを dBASE や Paradox の Blob 項目にロードするには

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
ビットマップを dBASE や Paradox の Blob 項目にロードするには,どうしたら良いですか?

A:
ビットマップイメージを dBASE や Paradox の Blob 項目にロードする方法は幾つかあります。 LoadFromFile メソッドと Assign メソッドを使用します。

  1. フォームに TTable コンポーネント(Table1)を配置します。
    DataBaseName プロパティにエリアスを設定
  2. Table1 をダブルクリックし,Bitmap(Blob項目)を追加します。
    (テーブルに Bitmap 項目があると仮定)
  3. フォームに TButton コンポーネント(Button1, Button2, Button3)を配置し,以下のコードを記述します。
   procedure TForm1.FormCreate(Sender: TObject);
   begin
     Table1.Open;
   end;

   procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
   begin
     Table1.Close;
   end;

   procedure TForm1.Button1Click(Sender: TObject);
     var
       B: TBitmap;
     begin
       B := TBitmap.Create;
       try
         B.LoadFromFile(
         'c:\program Files\Borland\delphi 2.0\images\splash\16color\athena.bmp');
         Table1.Edit;
         DBImage1.Picture.Assign(B);
         Table1.Post;
       finally
         B.Free;
       end;
   end;

   procedure TForm1.Button2Click(Sender: TObject);
   var
     B: TBitmap;
   begin
     B := TBitmap.Create;
     try
       B.LoadFromFile(
        'c:\program Files\Borland\delphi 2.0\images\splash\16color\earth.bmp');
       with Table1 do begin
         Edit;
         FieldByName('Bitmap').Assign(B);
         Post;
       end;
     finally
       B.Free;
     end;
   end;

   procedure TForm1.Button3Click(Sender: TObject);
   begin
     Table1.Edit;
     Table1Bitmap.Assign(nil);
     Table1.Post;
   end;

    テーブルを表示するときに「インデックスが古くなっています」のエラー

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
Delphi で Paradox のテーブルを表示しようとすると「インデックスが古くなっています」というエラーが表示されてテーブルの表示ができません。

A:
Paradoxのテーブル(*.db) とインデックスファイル(*.px) のタイムスタンプが違っている時などに,「インデックスが古くなっています」というエラーが表示される場合があります。

Paradox や Delphi 付属の DatabaseDesktop をお持ちの場合は,テーブルの再構築を行ってインデックスを簡単につけなおす事ができます。

どちらもお持ちでない場合には,Delphi から以下の手順でインデックスを付けなおす事ができます。

  1. *.db,*.mb以外のファイルをすべて削除して,インデックス情報を削除します。
  2. TTableのAddIndexメソッドを使用してインデックスを新しく作成します。

※ファイルの削除は,必ずバックアップを取ってから行うようにしてください。

    TDBGrid にテキストを書き込む処理は,どうしたら良いですか?

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
TDBGrid にテキストを書き込む処理は,どうしたら良いですか?

A:
TDBGrid.OnDrawDataCellイベントに,以下のコードを記述して処理できます。
以下では,グリッドの Company 項目のテキストの色を赤で表示します。
なお,Ver 2.0 では,OnDrawDataCell イベントの代わりに,OnDrawColumnCell イベントを使用します。

   procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
     DataCol: Integer; Column: TColumn; State: TGridDrawState);
   begin
     { 項目名が "Company" であれば }
     if Field.FieldName = 'Company' then
       { フォントの色を赤に変更 }
       (Sender as TDBGrid).Canvas.Font.Color := clRed;
     { グリッドにテキストを描画 }
     (Sender as TDBGrid).Canvas.TextRect(Rect, Rect.Left + 2, Rect.Top + 2,
                                         Field.AsString);
   end;

    テーブルのインデックスデータを取得するには,どうしたら良いですか?

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
テーブルのインデックスデータを取得するには,どうしたら良いですか?

A:
TTable の GetIndexNames メソッドが使用できます。
GetIndexNames メソッドは,Table で使えるすべてのインデックスの名前をList パラメータに追加します。

IndexDefs プロパティを使用すると,インデックス名,インデックスを構成する項目名,インデックス式,インデックスオプションなどのインンデックスについての情報を取得できます。

   procedure TForm1.Button1Click(Sender: TObject);
   begin
     ListBox1.Clear;
     Table1.GetIndexNames(ListBox1.Items);
   end;

IndexDefs オブジェクトの Count プロパティを基にしてループを行い,Table1 に関するインデックス名を取得します。

   procedure TForm1.Button2Click(Sender: TObject);
     var
       i: Integer;
     begin
       ListBox2.Items.Clear;
       with Table1 do begin
         Indexdefs.Update;
         if IndexDefs.Count > 0 then begin
           for i := 0 to IndexDefs.Count - 1 do
             ListBox2.Items.Add(IndexDefs.Items[i].Name)
         end;
       end;
   end;

以下の例では,インデックス名,インデックスを構成する項目名,インデックス式,インデックスオプションなどのインンデックスについての情報を TStringGrid に表示します。

   procedure TForm1.FormShow(Sender: TObject);
     var
       i: Integer;
       S: String;
     begin
       with Table1 do begin
         Open;
         {Refresh IndexDefs object}
         IndexDefs.Update;
         if IndexDefs.Count > 0 then begin
           {Set up columns and rows in grid to match IndexDefs items}
           StringGrid1.ColCount := 4;
           StringGrid1.RowCount := IndexDefs.Count + 1;
           {Set grid column labels to TIndexDef property names}
           StringGrid1.Cells[0, 0] := 'インデックス名';
           StringGrid1.ColWidths[0] := 150;
           StringGrid1.Cells[1, 0] := '項目名';
           StringGrid1.ColWidths[1] := 150;
           StringGrid1.Cells[2, 0] := '式';
           StringGrid1.ColWidths[2] := 150;
           StringGrid1.Cells[3, 0] := 'オプション';
           StringGrid1.ColWidths[3] := 200;
           {Loop through IndexDefs.Items}
           for i := 0 to IndexDefs.Count - 1 do begin
             {Fill grid cells for current row}
             StringGrid1.Cells[0, i + 1] := IndexDefs.Items[i].Name;
             StringGrid1.Cells[1, i + 1] := IndexDefs.Items[i].Fields;
             StringGrid1.Cells[2, i + 1] := IndexDefs.Items[i].Expression;
             if ixPrimary in IndexDefs.Items[i].Options then
               S := 'ixPrimary, ';
             if ixUnique in IndexDefs.Items[i].Options then
               S := S + 'ixUnique, ';
             if ixDescending in IndexDefs.Items[i].Options then
               S := S + 'ixDescending, ';
             if ixCaseInsensitive in IndexDefs.Items[i].Options then
               S := S + 'ixCaseInsensitive, ';
             if ixExpression in IndexDefs.Items[i].Options then
               S := S + 'ixExpression, ';
             if S > ' ' then begin
               {Get rid of trailing ", "}
               System.Delete(S, Length(S) - 1, 2);
               StringGrid1.Cells[3, i + 1] := S;
             end;
           end;
         end;
       end;
   end;

    TDBGrid から垂直スクロールバーを取り除くには,どうしたら良いですか?

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
TDBGrid から垂直スクロールバーを取り除くには,どうしたら良いですか?

A:
TDBGrid からスクロールバーを取り除くには,Paint メソッドをオーバーライドする必要があります。Paint メソッド内で,SetScrollRange API 関数をコールして,スクロール値の最小値と最大値を0に設定(これにより,スクロールバーを無効に)します。以下のコードを,NEWGRID.PAS として保存し,コンポーネントのインストールを行なうと,Data Controls に NoVertScrollDBGrid コンポーネントとして登録されます。

   unit NEWGRID;

   interface

   uses
     Windows, Classes, DBGrids;

   type
     TNoVertScrollDBGrid = class(TDBGrid)
     protected
       procedure Paint; override;
     end;

   procedure Register;

   implementation

   procedure TNoVertScrollDBGrid.Paint;
   begin
     SetScrollRange(Self.Handle, SB_VERT, 0, 0, False);
     inherited Paint;
   end;

   procedure Register;
   begin
     RegisterComponents('Data Controls', [TNoVertScrollDBGrid]);
   end;

   end.

    DatabaseName に設定されたエリアスからテーブルのパスを取得する

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
DatabaseName に設定されたエリアスからテーブルのパスを取得する事はできますか。

A:
BDE 関数 DbiGetDatabaseDesc( ) を使用して取得することができます。
以下はボタンを押したときにファイルのパスをShowMessageで表示するための手順です。

  1. uses節に BDE を追加します。
  2. ボタンの OnClick イベントハンドラに以下のように記述します。
procedure TForm1.Button1Click(Sender: TObject);
var
  vDBDesc: DBDesc;
  DirTable: String;
begin
  Check(DbiGetDatabaseDesc(PChar(Table1.DatabaseName), @vDBDesc));
  DirTable := Format('%s\%s', [vDBDesc.szPhyName, Table1.TableName]);
  ShowMessage(DirTable);
end;

    現在のレコード番号を取得するには,どうしますか?

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
現在のレコード番号を取得するには,どうしますか?

A:
データセットのベースが Paradox や dBASE のテーブルの場合は,BDE 関数を2,3回コールすることで解決します。BDE は,SQL のテーブルがベースとなるデータッセットのレコード番号をサポートしません。
dBASE のテーブルの場合は,取得したレコード番号は常に物理的なレコード番号です。データセットが TQuery または,データセットに範囲を指定した場合,取得した番号は,表示されるデータセットと必ずしも関連するとはいえません,どちらかと言うと,dBASE テーブルの物理的なレコード位置がベースとなります。

       unit RecNo;

       interface

       uses
         Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
         DB, DBTables, DbiProcs, DbiTypes, DbiErrs, Grids, DBGrids, StdCtrls;

       type
         TForm1 = class(TForm)
           Button1: TButton;
           DBGrid1: TDBGrid;
           Table1: TTable;
           DataSource1: TDataSource;
           Edit1: TEdit;
           procedure Button1Click(Sender: TObject);
         private
           { Private 宣言 }
         public
           { Public 宣言 }
         end;

       var
         Form1: TForm1;

       implementation

       {$R *.DFM}

       {$IFDEF VER90}   // Delphi 2
       function GetRecordNumber(Dataset: TDataset): Longint;
       {$ENDIF}
       {$IFDEF VER93}  // C++Builder 1
       function GetRecordNumber(Dataset: TDataset): Longint;
       {$ELSE}         // Delphi 3 以降
       function GetRecordNumber(Dataset: TBdeDataset): Longint;
       {$ENDIF}
       var
         CursorProps: CurProps;
         RecordProps: RECProps;
       begin
         {   データセットが Paradox または dBASE でないときは,0 を返す }
         Result := 0;
         with Dataset do
         begin
           { データセットはアクティヴか? }
           if State = dsInactive then
             raise EDatabaseError.Create('データセットは閉じているので,'+
                                         'この操作は行えません');

           { cursor の iSeqNums を取得する }
           Check(DbiGetCursorProps(Handle, CursorProps));

           { BDE cursor と データセットの cursor を同期させる }
           UpdateCursorPos;

           { カレントのレコードのプロパティで RecordProps を埋める }
           Check(DbiGetRecord(Handle, dbiNOLOCK, nil, @RecordProps));

           { 対象となるデータセットは? }
           case CursorProps.iSeqNums of
             0: Result := RecordProps.iPhyRecNum;  { dBASE   }
             1: Result := RecordProps.iSeqNum;     { Paradox }
           end;
         end;
       end;

       procedure TForm1.Button1Click(Sender: TObject);
       begin
         Edit1.Text := IntToStr(GetRecordNumber(Table1));
       end;

       end.

    パスワード入力のダイアログボックスの表示を抑制するには?

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
パスワード付きの Paradox テーブルを使用しています。テーブルを使用するフォームが表示される際に,パスワード入力のダイアログボックスを表示しないようにするにはどうしますか?

A:
テーブルの Active プロパティは,False に設定します,そうしないと,Session.Addpassword を行う前にパスワード入力のダイアログボックスが表示されます。
以下のコードのように Session.AddPassword() を フォームの OnCreate に記述して Active を True にします。
フォームの OnClose で Session.RemovePassword() でパスワードを削除します。すべてのカレントのパスワードを削除するには, Session.RemoveAllPasswords を使用します(Paradox のテーブルの場合)

unit Password;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Grids, DBGrids, DB, DBTables;

type
  TForm1 = class(TForm)
    Table1: TTable;
    DataSource1: TDataSource;
    DBGrid1: TDBGrid;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  Session.AddPassword('secret');
  Table1.Active := True;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Session.RemovePassword('secret')
end;

end.

    dBASE テーブルをパックするにはどうしますか?

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
dBASE テーブルをパックするにはどうしますか?

A:
TTable でオープンされた dBASE のテーブルをパックするには,DbiPackTable 関数を使用します。

uses に以下のユニットを追加します。

  Delphi 1.0:  DBITYPES, DBIPROCS, DBIERRS;
  Delphi 2.0:  BDE;

オブジェクトインスペクタから以下のプロパティを設定します。
Table1 の Active プロパティを False
Table1 の Exclusive プロパティを False

unit TblPack;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Bde,
  StdCtrls, DB, DBTables;

type
  TForm1 = class(TForm)
    Table1: TTable;
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
begin
  
   Check(DbiPackTable(Table1.DbHandle, Table1.Handle, Nil, szDBASE, TRUE));
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  Table1.Active := False;
  repeat { 成功するまで, または[キャンセル]ボタンが押されるまで }
    try
      Table1.Exclusive := True; { Table1 がオープンするか調べます }
      Table1.Active := True;
      Break; { エラーがなければループを終了します }
    except
      on EDatabaseError do

      { 再試行してもいいか尋ねます }
        if MessageDlg('Could not open Table1 exclusively - OK to retry?',
            mtError, [mbOK, mbCancel], 0) <> mrOK then
          raise; { 再試行できない場合は例外を再び生成して中止します }
      { それ以外の場合はループを再開します }
    end;
  until False;
end;

end.

    空白を含む項目名をSQL構文で使用する場合の注意

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

空白を含む項目名をSQL構文で使用する場合の注意

DelphiのTQueryコンポーネントでSQL構文を使用する場合,空白や特殊な文字を含む構文の扱いには注意が必要です。

Delphiのデモデータ,Biolife.DBを例にとって説明します。
空白を含まない場合には,通常は以下のように記述します。

SELECT
 Species No,
 Category,
 Common_Name,
 Species Name,
 Length (cm),
 Length_In,
 Notes,
 Graphic
FROM
 BIOLIFE.DB

しかし,この例の場合にはSpecies No,Species Name,Length (cm)などの項目に空白文字が含まれています。そのため,このSQL構文を実行すると構文エラーが発生します。

このSQL構文を正しく実行させるためには,以下の変更が必要です。
1: すべての項目を「 ' 」か「 " 」で囲みます。
2: 第2に,テーブルリファレンスを「 . 」を囲んだ項目名の前につけます。
SQL構文は以下のようになります。

SELECT
 BIOLIFE."Species No",
 BIOLIFE."Category",
 BIOLIFE."Common_Name",
 BIOLIFE."Species Name",
 BIOLIFE."Length (cm)",
 BIOLIFE."Length_In",
 BIOLIFE."Notes",
 BIOLIFE."Graphic"
FROM
 "BIOLIFE.DB" BIOLIFE

上の構文では項目名の前に付加するテーブルリファレンスとして,BIOLIFEを使用しています。このリファレンスは,dBASE や Paradox テーブルを使うときのファイル名を「 ' 」や「 " 」で囲んだ後に続けて定義します。

注: このSQL構文は,必要なエリアスが設定されていて,既にオープンされている場合にのみ有効です。DatabaseNameプロパティにエリアスを設定する必要があります。

もし,エリアスを設定していない場合でも,以下のように設定して空白や記号を含む項目名を扱う事ができます。

SELECT
 "C:\Program Files\Borland\Delphi 2.0\DEMOS\DATA\BIOLIFE.DB"."Species No",
 "C:\Program Files\Borland\Delphi 2.0\DEMOS\DATA\BIOLIFE.DB"."Category",
 "C:\Program Files\Borland\Delphi 2.0\DEMOS\DATA\BIOLIFE.DB"."Common_Name",
 "C:\Program Files\Borland\Delphi 2.0\DEMOS\DATA\BIOLIFE.DB"."Species Name",
 "C:\Program Files\Borland\Delphi 2.0\DEMOS\DATA\BIOLIFE.DB"."Length (cm)",
 "C:\Program Files\Borland\Delphi 2.0\DEMOS\DATA\BIOLIFE.DB"."Length_In",
 "C:\Program Files\Borland\Delphi 2.0\DEMOS\DATA\BIOLIFE.DB"."Notes",
 "C:\Program Files\Borland\Delphi 2.0\DEMOS\DATA\BIOLIFE.DB"."Graphic"
FROM
 "C:\Program Files\Borland\Delphi 2.0\DEMOS\DATA\BIOLIFE.DB"

    DBGridの項目の表示を動的に変更する

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
DBGridのセルの幅や色などの変更は,設計時には項目エディタを使用できますが,実行時に動的に変更することはできますか?

A:
DBGridのセルの設定は,Columnsプロパティを使用して行うことができます。
以下のコードは動的にセルの幅と色を変更します。

var
   i:Integer;
begin
     for i := 0 to DBGrid1.FieldCount -1 do
     begin
          DBGrid1.Columns[i].Color := clBlue;
          DBGrid1.Columns[i].Width := 100;
     end;
end;

    MEMO コンポーネントに入力した内容をデータベースのメモ型項目に追加する

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
MEMO コンポーネントに入力した内容をデータベースのメモ型項目に追加するにはどうすればよいでしょうか。

A:
Assignメソッドを使用できます。
以下のコードは MEMO コンポーネントをMEMO型項目に追加して保存するものです。

各項目
Tableコンポーネント: Table1
テーブルのメモ型項目: KOUMOKU
MEMOコンポーネント: Memo1

begin
   Table1.Edit;
   Table1.FieldByName('KOUMOKU').Assign(Memo1.Lines);
   Table1.Post;
end;

    テーブルに格納されているグラフィックデータを TBitmap などの変数に取り出す

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
テーブルに格納されているグラフィックデータを TBitmap などの変数に取り出すことはできますか?

A:
テーブルに格納されているグラフィックデータは,TGraphicField 型になります。
この型のデータを TBitmap に読み込んで使用するには,Assign メソッドを利用します。
以下のコードは,TBitmap 型の変数 bmp に,Delphi のサンプルデータ Biolife.DBのGraphic 項目のデータを格納して,イメージコンポーネントに表示します。

var
   bmp : TBitmap;
begin
     bmp := TBitmap.Create;
     bmp.Assign(TGraphicField(Table1.FieldByName('Graphic')));
     Image1.Picture.Graphic := bmp;
     bmp.Free;
end;

    実行時に Query に変数を渡すにはどうしたらよいですか?

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
実行時に Query に変数を渡すにはどうしたらよいですか?

A:
まず,変数を使用する Query を TQuery の SQL プロパティに以下のように記述します。

   SELECT Country."Name", Country."Capital", Country."Population"
   FROM Country
   WHERE Country."Population" > :val

変数名に val を使用していますが,他の任意の変数名を使用してもかまいません。
次に,TQuery の Params プロパティをクリックすると,パラメータ名にval が入っているダイアログボックスが現れます。ここで,データの種類に適切な型を設定します。この例では Integer を選択します。

さらに,引数の値を設定するコードを記述します。
ここでは, TEdit からの値を設定しています。

   procedure TForm1.Button1Click(Sender: TObject);
   begin
     with Query1 do
     begin
       Close;
       ParamByName('val').AsInteger := StrToInt(Edit1.Text);
       Open;
     end;
   end;

もし,Query に LIKE 演算子を使用するには,以下のように行えます。
ここでは,DBDEMOS エリアスの Customer.db を使用しています。
TQuery の SQL プロパティのコードを記述します。

  SELECT * FROM CUSTOMER
  WHERE Company LIKE :CompanyName

TQuery の Params プロパティをクリックすると,パラメータ名に CompanyName が入っているダイアログボックスが現れます。ここで,データの種類に String を選択します。

引数の値を設定するコードを記述します。 TEdit からの値を設定しています。

  procedure TForm1.Button1Click(Sender: TObject);
  begin
    with Query1 do
    begin
      Close;
      ParamByName('CompanyName').AsString := Edit1.Text + '%';
      Open;
    end;
  end;

ParamByName の代わりに,Params[パラメータの番号] を使用することもできます。

ParamByName('CompanyName').AsString := Edit1.Text + '%';

Params[0].AsString := Edit1.Text + '%';

とも記述できます。

    ソフト削除のマークが付いた dBASE のレコードの表示

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
ソフト削除のマークが付いた dBASE のレコードを表示するには,どうしますか?

A:
dBASE テーブルでは,テーブルがパックされるまではテーブルから取り除かれません。テーブルがパックされるまでは削除されたレコードは,実際は「削除される」というマークが付いただけです。表示されないけれども,存在するレコードを表示するには,BDE API 関数の DbiSetProp() をコールするShowDeleted() 関数を用いて削除マークの付いたレコードを表示できます。
この関数を使用する場合,テーブルのクローズと再オープンを行なう必要はありません。ShowDeleted() は,引数として TTable と論理変数を受け取ります。論理変数は,削除されたレコードを表示するかどうか決定します。

unit Deleted;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls, DBCtrls, Grids, DBGrids, DB, DBTables;

type
  TForm1 = class(TForm)
    Table1: TTable;
    DataSource1: TDataSource;
    DBGrid1: TDBGrid;
    DBNavigator1: TDBNavigator;
    CheckBox1: TCheckBox;
    procedure CheckBox1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
    procedure ShowDeleted(Table: TTable; ShowDeleted: Boolean);
  end;

var
  Form1: TForm1;

implementation
uses DBITYPES, DBIERRS, DBIPROCS;

{$R *.DFM}

procedure TForm1.ShowDeleted(Table: TTable; ShowDeleted: Boolean);
var
  rslt: DBIResult;
  szErrMsg: DBIMSG;
begin
  Table.DisableControls;
  try
    Check(DbiSetProp(hDBIObj(Table.Handle), curSOFTDELETEON,
      LongInt(ShowDeleted)));
  finally
    Table.EnableControls;
  end;
  Table.Refresh;
end;
procedure TForm1.CheckBox1Click(Sender: TObject);
begin
  ShowDeleted(Table1, CheckBox1.Checked);
end;

end.

    TTable コンポーネントで,現在のレコード番号を取得するには

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
TTable コンポーネントで,現在のレコード番号を取得するには,どのようにすればよいでしょうか?

A:
TTable コンポーネントは dBASE や Paradox のようなローカルテーブルだけでなく,SQL サーバー上のデータベースにも対応できるよう汎用的に作られています。SQL サーバーのデータベースではレコード番号というものが存在しないため,TTable コンポーネントではレコード番号を取得できません。

※Delphi(CD-ROM版) では \EXTRAS\EXAMPLES\RECNO ディレクトリに,dBASE やParadox テーブルのレコード番号を取得するプログラム例が含まれています。

    dBASE テーブルのインデックスで IsIndexField メソッドを使うには

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
dBASE テーブルをオープンしていますが,インデックスが付いている項目に対して IsIndexField メソッドを使っても False が返されてしまいます。しかし,GetIndexNames メソッドを使うと,すべてのインデックス項目が正しく取得できます。また,Paradox テーブルに対してはキー項目に対して True が返されます。 dBASE テーブルのインデックスで IsIndexField を使うには,どうすればよいのでしょうか?

A:
IsIndexField は,アクティブなインデックスかどうかを調べるメソッドです。
Paradox では,テーブルをオープンした時点でキー(一次インデックス)が有効になりますが,dBASE では必ずどのインデックスを使うかを指定する必要があります。たとえば,\DELPHI\DEMOS\DATA にある ANIMALS.DBF であれば IndexName に 'NAME' を代入すれば,NAME 項目がインデックスとして使えるようになります。

    TDBGrid コンポーネントの現在選択中のレコードの位置を知るには

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
TDBGrid コンポーネントの現在選択中のレコードの位置を知るには,どうすればよいでしょうか?

A:
次のプログラムは,TDBGrid に表示されている位置を追跡するプログラム例です。
MyDBGridDrawDataCell メソッドは,TDBGrid の OnDrawDataCell イベントハンドラとして定義され,グリッドが再描画されるたびにグローバル変数 Col, Row を更新します。このプログラムコードを割り当てておけば,グローバル変数 Col,Row を参照するだけで,現在選択されている桁と行を知ることができます。

var
  Col, Row: Integer;
 
procedure TForm1.MyDBGridDrawDataCell(Sender: TObject; const Rect: TRect;
  Field: TField; State: TGridDrawState);
var
  RowHeight: Integer;
begin
  if gdFocused in State then
  begin
    RowHeight := Rect.Bottom - Rect.Top;
    Row := (Rect.Top div RowHeight) - 1;
    Col := Field.Index;
  end;
end;

    TDBGrid コンポーネントで,[Enter](リターン)キーで項目を移動させたい

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
TDBGrid コンポーネントで,[Enter](リターン)キーで項目を移動させたいのですが,どうすればよいでしょうか?

A:
OnKeyDown と OnKeyPress イベントハンドラを定義して,[Enter] キーを [Tab] キーに置き換えます。
フォームの KeyPreview プロパティは True に設定しておきます。

   procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
     Shift: TShiftState);
   begin
     if Key = VK_RETURN then
       Key := VK_TAB;
   end;

   procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
   begin
     if Key = #13 then
       Key := #9;
   end;

    TDBGrid コンポーネントで選択中の行全体をハイライト表示するには

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
TDBGrid コンポーネントで選択中の行全体をハイライト表示するには,どうすればよいでしょうか?

A:
Options プロパティの dgRowSelect を True にしてください。TDBGrid にフォーカスがないときにも選択状態を表示しておくためには,dgAlwaysShowSelection を True にしてください。

    TDBEdit コンポーネントでも入力マスク (EditMask) を設定するには

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
TDBEdit コンポーネントでも入力マスク (EditMask) を設定するには,どうすればよいでしょうか?

A:
TDBEdit コンポーネントには EditMask プロパティはありませんが,テーブルにフィールドを追加することで,入力マスクを指定できます。まず,フォーム上に配置した TTable コンポーネントをダブルクリックして,項目エディタを呼び出します。[追加]ボタンを押して,使いたい項目(必要ならばすべて)を指定します。
こうすることで適当な項目(TxxxField)オブジェクトがフォームに追加され,項目エディタのリストボックスに表示されます。リストボックスに表示されているそれぞれの項目を選ぶと,対応するオブジェクトのプロパティをオブジェクトインスペクタで設定できます。項目オブジェクトには EditMask プロパティが用意されているため,ここで入力マスクを指定すれば TDBEdit や TDBGrid コンポーネントで文字列を編集する際に,この入力マスクが使われます。

    TDBGrid で選択中のセルの色を変更するにはどうすればよいでしょうか?

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
TDBGrid で選択中のセルの色を変更するにはどうすればよいでしょうか?

A:
TDBGrid コンポーネントの OnDrawDataCell イベントを処理することで,データ表示を自由に制御できます。選択中のセルの色を変更するプログラム例を以下に示します。

procedure TForm1.DBGrid1DrawDataCell(Sender: TObject; const Rect: TRect;
  Field: TField; State: TGridDrawState);
begin
  if gdFocused in State then
    with (Sender as TDBGrid).Canvas do
    begin
      Brush.Color := clNavy;  { 背景は clNavy(暗い青) }
      FillRect(Rect);
      Font.Color := clWhite;  { 文字は clWhite(白) }
      { この場合,テキストは常に左端から表示される }
      TextOut(Rect.Left, Rect.Top, Field.AsString);
    end;
end;

すべてのセルの描画を自分で管理する場合は,DefaultDrawing プロパティをFalse に設定します。この場合は,必ず OnDrawDataCell イベントを処理する必要があります。

    TMemo コンポーネントの内容を Paradox テーブルの TMemoField に代入するには

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
TMemo コンポーネントの内容を Paradox テーブルの TMemoField に代入するには,どうすればよいでしょうか。

A:
Paradox テーブルの Memo フィールド名を「Note」とすると,Memo1 コンポーネントの内容を割り当てるためには,次のようにします。

Table1.FieldByName('Note').Assign(Memo1.Lines);

このとき,Edit や Post メソッドを使ってテーブルの編集状態への移行や,変更内容の登録をするようにしてください。

    既存のテーブルから固定長の ASCII テキスト形式のテーブルを作成するには

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
既存のテーブルから固定長の ASCII テキスト形式のテーブルを作成するには,どうすればよいでしょうか?

A:
以下のプログラムを参考にしてください(TTable コンポーネントのため,uses 節には DBTables を追加しておく必要があります)。

procedure TForm1.Button1Click(Sender: TObject);
var
  SrcTbl, DestTbl: TTable;
begin
  SrcTbl := TTable.Create(Self);
  with SrcTbl do
  begin
    DatabaseName := 'DBDEMOS';
    TableName := 'CUSTOMER.DB';
    Open;
  end;
  DestTbl := TTable.Create(Self);
  with DestTbl do
  begin
    DatabaseName := 'DBDEMOS';
    TableName := 'NEWTBL.TXT';
    TableType := ttASCII;
    CreateTable;
    Open;
    Edit;
    BatchMove(SrcTbl, batCopy);
    Close;
    Free;
  end;
  SrcTbl.Close;
  SrcTbl.Free;
end;

    TDBChart コンポーネントを使用してグラフを作成するには

該当するバージョン:Delphi 3.0/Delphi3.1,Delphi4

TDBChart コンポーネントを使用してグラフ を作成するには:

グラフデータをテーブルあるいは SQL 問い合わせから取り出す場合は,TDBChart コンポーネントを使用してください。

  1. TTable をフォームに配置し,DataBaseName プロパティを 'DBDEMOS',TableName プロパティを 'ANIMALS.DBF' に設定します。
  2. Table1.Active プロパティを True に設定します。
  3. Data Controls|DBChart をフォームに配置します。
  4. TDBChart 上で右マウスボタンをクリックして,チャートの編集を選択します。
  5. 系列|追加を選択すると TeeChart ギャラリが表示されます。ここから1つ選択後 OK をクリックします。たとえば,縦棒を選択します。
  6. DBChart1 の編集の系列名をダブルクリックするか系列のタブを選択します。
    ここでは,系列についての様々な設定が行えます。
  7. データのタブを選択して,リストボックスからデータセットを選択します。

ここでは,系列で使用するデータセットを定義します。フォームには,テーブルとデータセットがあり,テーブルはアクティブに設定してあります。ここで,データセット(D) の下矢印をクリックすると Table1 が表示されます。

  1. データセット(D)には,Table1 を選択します。
  2. ラベル(L)には,NAME を選択します。ここは,オプションです。
  3. Barには,WEIGHT を選択します。ここは必須です。
  4. 閉じるをクリックすると,縦棒チャートが表示されます。
    F9 を押して実行した時と全く同じ縦棒チャートが表示されます。

    "Internal Error; Near: クエリー shellmgr" のエラーが表示

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
Local InterBase: "Internal Error; Near: クエリー shellmgr" のエラーが表示されます。このエラーの原因および対処方法はどうしたら良いですか?

A:
これは,Dell のマシンで発生する場合があります。NT 4.0 がプリインストールされた Dell Pentium Pro のマシンで発生します。レジストリの設定を変更することで,Dell のマシンでエクスプローラの拡張子をロードできるようになります。

対処方法:

  1. Regedit を起動します。
  2. 以下のキーを確認します:
     HKEY_LOCAL_MACHINE
       \SOFTWARE
         \Microsoft
           \Windows NT
             \CurrentVersion
               \WinLogon
                 \Shell

Explorer.exe userhook.??? となっています。

  1. Explorer.exe に変更します。
  2. マシンを再起動します。

この件については,InstallShield の Web サイトで公開されており,InterBase のインストールの問題ではなく,InstallShield の問題です。

    Microsoft のデータベースやテーブルにアクセス

該当するバージョン:Delphi 3.0/Delphi3.1,Delphi4

Q:
Microsoft のデータベースやテーブルにアクセスするために必要なソフトウェアは何ですか?

A:
Microsoft の DAO がインストールされていなければなりません。
現在サポートされている DAO のバージョンは以下のとおりです。

  • DAO 3.0 (Access 95) - Delphi 3 以降
  • DAO 3.5 (Access 97) - Delphi 4 以降

    Access ネイティブドライバを使用してマルチスレッドプリケーションを作成

該当するバージョン:Delphi 3.0/Delphi3.1,Delphi4

Q:
Access ネイティブドライバを使用してマルチスレッドプリケーションを作成することができますか?

A:
DAO 3.0 がスレッドセーフではないため,Borland の MSACCESS ネイティブドライバも含めて)によるデータベースへのアクセスはメインスレッドから行う必要があります。スレッドを使用するアプリケーションがある場合,スレッド内で MSACCESS ドライバによるデータベースを処理する操作を行なわなければ問題ありません。

    Access ネイティブドライバの制限

該当するバージョン:Delphi 3.0/Delphi3.1,Delphi4

Q:
Access ネイティブドライバの制限は何ですか?

A:
BCD(binary coded decimal)はサポートしていません。DbiAddIndex によるキー違反のテーブルは作成されません(他のすべての DbiAddIndex の機能はサポートされます)。QBE,異種間のクエリー,Local SQL を使用したクエリーはサポートされません。SDK には,DbiDoRestructure と DbiRegenIndex はありません。
同じセッション内であっても,TTable.Exclusive が True に設定されたテーブルを再オープンすることはできません。

    クエリーやストアドプロシージャの入力パラメータとして BLOB を使用

該当するバージョン:Delphi 3.0/Delphi3.1,Delphi4

Q:
クエリーやストアドプロシージャの入力パラメータとして BLOB を使用できますか?

A:
可能です。しかし,BLOB パラメータの最大値は 255 バイト以下です。BDE 4.0 より古いバージョンでは,BLOB を入力パラメータとして使用することはできません。

    Access ネイティブドライバを使用するアプリケーションを配布

該当するバージョン:Delphi 3.0/Delphi3.1,Delphi4

Q:
Access ネイティブドライバを使用するアプリケーションを配布する場合,他にどのようなファイルを添付する必要がありますか?

A:
BDE 用の DLL ファイルに加えて,BDE のAccess ドライバファイルが必要です。
また, Access ドライバファイルが動作するためには, DAO と JET エンジンが実行環境に存在することが前提条件となります。

Access ドライバファイルと DAO Jet エンジンのバージョンは以下のように対応しております。

  • Access 95 および Jet Engine 3.0 の場合は IDDAO32.DLL
  • Access 97 および Jet Engine 3.5 の場合は IDDA3532.DLL

BDE の MSACCESS ドライバは自由に配布することができますが, アプリケーションを再配布する前に,DAO と JET エンジンを配布する権利があるかどうか確認してください。

    代替システムデータベース

該当するバージョン:Delphi 3.0/Delphi3.1,Delphi4

Q:
デフォルトとは異なるシステムデータベースはどのように設定しますか?

A:
BDE 4.00 では,システムデータベースを変更する設定はありません。Access ドライバーはデフォルトのシステムデータベースを使用します。
また BDE 5.00 以降の BDE では, BDE Administrator の [環境設定] タブから, [環境設定 | Drivers | Native | MSACCES] を選択して, [SYSTEM DATABASE] 項目を設定することで, システムデータベースを変更することができます。

    BDE 環境設定ユーティリティ

該当するバージョン:Delphi 3.0/Delphi3.1,Delphi4

Q:
新しい BDE 環境設定ユーティリティがありますか?

A:
はい。BDE 環境設定ユーティリティは新しく BDE Administrator(BDEADMIN.EXE) になりました。BDE Administrator は,Delphi データベースエクスプローラのようなユーザーインターフェースを採用しています。

    Access ドライバの特徴

該当するバージョン:Delphi 3.0/Delphi3.1,Delphi4

Q:
新しい Access ドライバの特徴は何ですか?

A:
システムに Microsoft の JET エンジン(Microsoft Access などに含まれています)がインストールされていると,BDE の Access ネイティブドライバを使用してMicrosoft Access テーブルを開いたり作成することができます。詳しくは "データベース" の項目を参照してください。

    SQL パラメータバインドのサポート

該当するバージョン:Delphi 3.0

Q:
どのような種類の SQL パラメータバインドをサポートしていますか?

A:
BDE は新たに,BLOB と 255 文字を越える文字列のパラメータバインドをサポートします(MSACCESS ドライバを除く)。
詳しくは,SQL 入力パラメータとしての BLOBを参照してください。

    無効な BLOB ハンドルエラー

該当するバージョン:Delphi 3.0/Delphi3.1,Delphi4

Q:
"無効な BLOB ハンドルエラー" のエラーが表示:
このエラーの原因および対処方法はどうしたら良いですか?

A:
エラーの原因が,ライブ問い合わせでない(通常の)問い合わせ,または,インデックスの無いテーブルにある場合は,新しい BDE 4.0 の環境パラメータの "BLOBS TO CACHE" の値を増やすことで問題が解決されます。この設定は,クライアント上でキャッシュされる BLOB の数を決定します。無効なテーブルのオープンやクエリーを使用して無効な BLOB をフェッチ(fetch)するアプリケーションは,クライアントで利用可能なリソースに依存してキャッシュできる BLOB 数の制限を行えます。
100 に値を設定することは,アプリケーションは,最高 100 BLOB レコードをキャッシュして動作すると言うことです。100 以上をフェッチして 100 スクロールバックすると,"レコードバッファの BLOB ハンドルは無効です" のエラーメッセージが表示されます。

NOTE: このパラメータは,ライブテーブルのオープンには適用されません。

デフォルト値: 64 (64 から 65536 の範囲で指定できます)

    TField オブジェクトに DefaultExpression の指定を行うには

該当するバージョン:Delphi 3.0/Delphi3.1,Delphi4

Q:
TField オブジェクトに DefaultExpression の指定を行うにはどうしますか?

A:
項目の属性を設定して,使用するテーブルの項目に関連づけたとします。
オブジェクトインスペクタで値を文字列で設定できますが,実行時に値は反映され ません。
実行時に以下のように,TField.DefaultExpression を設定すると:

MyField.DefaultExpression := 'MyValue';

コンパイルは通りますが,DBNavigator の+をクリックして実行時にテーブルに新しいレコードを作成した際に,デフォルトの値は設定されません。実行時にデフォルトの値を設定するには,コードを以下のように変更します。

MyField.DefaultExpression := '''MyValue''';

オブジェクトインスペクタからは,'MyValue' と入力します。オブジェクトインスペクタでは,シングコート(')を使用します。

    ポストされる前に,TDBGrid 値を取得

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
ポストされる前に,TDBGrid 値を取得:
Grid に入力される値を取得するには,どうしますか?

A:
TDBGrid の TInPlaceEdit コントロールを検証することで,TDBGrid に入力される値を知ることができます。TInPlaceEdit コントロールは動的に作成されるため,常に存在すると仮定することはできない点に注意してください。
以下のコードは,grid のコラムで編集中のデータを表示します。

   procedure TForm1.DBGrid1KeyUp(Sender: TObject; var Key: Word;
     Shift: TShiftState);
   var
     B: byte;
   begin
     for B := 0 to DBgrid1.ControlCount - 1 do
       if DBGrid1.Controls[B] is TInPlaceEdit then
       begin
         with DBGrid1.Controls[B] as TInPlaceEdit do
         begin
           Label1.Caption := 'Text = ' + Text;
         end;
       end;
   end;

機能の詳細については,Delphi3 のヘルプファイルから TinPlaceEdit を参照してください。

    動的に SQL を発行して取り出した数値項目を3桁区切りで表示する

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
動的に SQL を発行した場合,取り出された数値項目を3桁区切りで表示する事はできますか。

A:
DisplayFormat プロパティを利用できます。以下のサンプルは動的に SQL を発行した後,Salary 項目について3桁区切りで表示できるよう,DisplayFormat を設定しています。

   with Query1 do
   begin
     Close;
     SQL.Clear;
     SQL.Add('SELECT * FROM EMPLOYEE.DB');
     Open;
   end;
   // FieldByName で指定した項目を TFloatField で型キャストします。
   TFloatField(Query1.FieldByName('Salary')).DisplayFormat := '#,##0';

    最大カーソル数を超えています

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
参照整合性が 70 個ほどあるテーブルの親側のテーブルを Delphi で作ったアプリケーションからレコードを削除しようとした時に「最大カーソル数を超えています。」と言うエラーが出てしまいました。

A:
初期のOpenできるカーソル数は少ないですから,Table を一度にたくさん開くと上記のようになります。対処するには RDBMS 側の最大カーソル数を増やしてください。
初期値は通常は 70 から 100 に設定されていますが,運用するには最低でも 250 程度は必要でしょう。
(詳細な方法については各 RDBMS の DBA マニュアルを参照してください。)

    TDatabase コンポーネントの DatabaseName プロパティに絶対パスを指定する方法

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
TDatabase コンポーネントの DatabaseName プロパティに絶対パスを指定してデータにアクセスする方法

A:
Paradox または dBASE データベースへ接続するときは,DatabaseName はエリアス名ではなく絶対パス名にすることもできます。
Database コンポーネントをデータセットコンポーネント (Table や Query など) に接続してデータにアクセスするには以下の手順を参考にしてください。

  1. フォームに TDatabase,TTable,TDatasource,TDBGrid を配置します。
  2. それぞれのコンポーネントにプロパティを設定します。
    TDatabase
       DatabaseName     DB1
       Params           PATH="c:\program files\borland\delphi 3\demos\data"
       TransIsolation   tiDirtyRead

    TTable
       DatabaseName     DB1      (TDatabase の DatabaseName で設定した値)
       TableName        ANIMALS.DBF

    TDatasource     
       Dataset          Table1

    TDBGrid      
       DataSource       DataSource1
  1. TDatabase の Connected プロパティ,TTable の Active プロパティ を Trueにして完了します。

    TDBGrid で OnClick の機能を追加

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

TDBGrid には OnClick イベントは存在しませんが,OnClick イベントが存在するように見せることは可能です。ここで紹介する方法は,他のオブジェクトのプロパティにも応用できます。継承元で可能であれば継承先でも可能にさせる方法です。
以下のコードのように THack として型変換されたコントロールは Windows からのクリックメッセージを正常に処理できます。他のコントロールの OnClick を DBGrid1の OnClick に代入すると OnClick イベントの機能がないにもかかわらずその機能を使用できるようになります。

unit HACK1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Db, DBTables, Grids, DBGrids, StdCtrls;

type
  THack = class(tcontrol);

  TForm1 = class(TForm)
    Button1: TButton;
    DBGrid1: TDBGrid;
    Table1: TTable;
    DataSource1: TDataSource;
    procedure Button1Click(Sender: TObject);
    procedure FormClick(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
begin
  THack(DBGrid1).Controlstyle :=
  THack(DBGrid1).Controlstyle + [csClickEvents];  { csClickEvents を追加 }
  THack(DBGrid1).OnClick := Form1.OnClick;        { Form1 の OnClick を代入 }
end;

procedure TForm1.FormClick(Sender: TObject);
begin
  MessageBeep(0);
  Application.ProcessMessages;
end;

end.

    Paradox テーブルの再構築

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
Paradox テーブルを使用したアプリケーションを作成していますが,レコードの削除を行ってもファイルサイズが変わりません。

A:
無駄な I/O アクセスを減らすためにそのような仕様となっています。
一般的な DB ファイルはほぼそのようになっており,これを最適化するためにはテーブルの再構築を行う必要があります。
DataBase DeskTop あるいは Paradox があればそちらで再構築を行っていただいても結構ですし,BDE の API を利用して再構築を行うことも可能です。
以下に BDE の DbiDoRestructure を用いて再構築する例を記載します。

{ DbiDoRestructure を実行する前に該当するテーブルへの参照は全て閉じて下さい。
 共有の問題が発生します。}
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, BDE, Db, DBTables;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Table1: TTable;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var
  hDb: hDbiDb;
  TblDesc: CRTblDesc;

begin
  
  // Tableはここでオープンします。事前に参照している場合はは全て閉じておきます。
  Table1.Open;  
  try
    Screen.Cursor:=crHourGlass;
    FillChar(TblDesc, sizeof(CRTblDesc), #0);

    Table1.DisableControls;
    Table1.Close;

    Check(DbiOpenDatabase(
            'TEST', //pszDbName   環境設定ファイルで定義されたエリアス名
               nil, //pszDbType   データベースの種類の文字列へのポインタ
      dbiReadWrite, //eOpenMode   オープンモード
       dbiOpenExcl, //eShareMode  共有モード 排他オープン
               nil, //pszPassword パスワード文字列へのポインタ
                 0, //iOptFlds
               nil, //pOptFldDesc
               nil, //pOptParams
               hDb  //phDb        データベースハンドルへのポインタ
         ));

    TblDesc.bPack:=True;
    StrPCopy(TblDesc.szTblName, Table1.TableName);
    StrCopy(TblDesc.szTblType, szParadox);

    Check(DbiDoRestructure(
               hDb,  //hDB             データベースハンドル
                 1,  //iTblDescCount   テーブルディスクリプタの数 1
          @TblDesc,  //pTblDesc        CRTblDesc 構造体へのポインタ
               nil,  //pszSaveAs       再構築テーブルへのポインタ
               nil,  //pszKeyviolName  キー違反テーブルへのポインタ
               nil,  //pszProblemsName Problem テーブルへのポインタ
             False   //bAnalyzeOnly    未使用
         ));

  finally
    Check(DbiCloseDatabase(hDb));
    Table1.EnableControls;
    Table1.Open;
    Screen.Cursor:=crDefault;
  end;{try}
end;

end.

    DBGrid の列ごとにかな漢字変換を制御するには

該当するバージョン:Delphi 3.0/Delphi3.1,Delphi4

Q:
DBGrid の列ごとに,かな漢字変換を制御するにはどうしたらよいでしょうか。

A:
かな漢字変換を制御するには,SetImeMode メソッドを使用できます。
このメソッドは,Controls.pas で定義されています。
SetImeMode の第1引数には,コントロールのハンドルを指定します。
第2引数には,IME がユーザーのキーストロークを処理する方法を設定します。
以下の例では,TDBGrid の OnColEnter イベントに記述してありアクティブな列が変更されるたびに IME モードが変更されます。

procedure TForm1.DBGrid1ColEnter(Sender: TObject);
begin
  with DBGrid1 do
    case SelectedField.FieldNo of       // FieldNo は,1から開始
      1: SetImeMode(Handle, imSAlpha);
      2: SetImeMode(Handle, imKata);
      3: SetImeMode(Handle, imHira);
      4: SetImeMode(Handle, imSKata);
      5: SetImeMode(Handle, imDontCare);
    end;
end;

    TDatabase を使用したパスワード入力ダイアログの抑制方法

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
データベースアプリケーションの実行時にパスワード入力ダイアログを表示したくありません。どのようにすればダイアログを表示しないようにできますか。

A:
TDatabase を使用する事でパスワードダイアログを抑制することができます。
以下の手順に従って,データベースアプリケーションを実行する時にパスワード入力ダイアログの表示を抑制する事ができます。

[手順] ※ここでは InterBase のデフォルトのユーザ名,パスワードを使用した手順について説明します。

  1. フォームに TDatabase コンポーネントを配置します。
  2. TDatabase の AliasName に IBLOCAL を設定します。
  3. DatabaseName に任意の名前を設定します。
  4. LoginPrompt プロパティを False に設定します。
  5. Params プロパティをクリックして「文字列リストの設定」ダイアログを表示して,以下のように記述します。
USER NAME=SYSDBA
PASSWORD=masterkey
  1. Connected プロパティを True に設定します。

使用する時には,TTable または TQuery の DatabaseName プロパティに [手順 3.] で設定した名前を選択します。

    テキストテーブルで使用するスキーマファイルについて

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

スキーマファイルは,ASCII テーブルとデータベースとの間でデータをやり取り(エクスポートやインポート)する場合に使用し,テーブルの構造とその列(項目)のデータ型に関する情報が入ったテキストファイルで,拡張子は .SCH です。

TBatchMove コンポーネントでテーブルを ASCII 形式にコピー(エクスポート)するとスキーマファイルと ASCII データファイルが自動的に作成されます。この場合, ASCII テーブルは常に Fixed 形式(固定長)のファイルとして作成されます。なお,ASCII テーブルを作成する場合,Table コンポーネントの TableType を ttASCII と指定してください。

スキーマファイルの構造

スキーマファイル内のすべての情報は,大文字と小文字を区別します。以下にスキーマファイルの例を示します。

[CUSTOMER]                      // ファイル名 (拡張子なし)
FILETYPE = Delimited            // ファイル形式:Delimited または Fixed
CHARSET = ascii                 // 言語ドライバ名
DELIMITER = "                   // 文字項目 (フィールド) の囲み文字
SEPARATOR = ,                   // 項目間 (フィールド) の区切り文字
Field1 = Name,CHAR,12,0,0       // 項目 (フィールド) 情報
Field2 = Salary,FLOAT,8,2,12

一行目(ファイル名)

半角の角括弧に囲まれたテーブル名を指定します。拡張子は指定しません。

FILETYPE

テキストファイルの形式として, Fixed (固定長テキスト)または Delimited(カンマ付きテキスト)のどちらかを指定します。
Fixed 形式のファイルでは,ファイル内の各項目は常に固定文字数を取り,必要に応じてスペースが埋められます。
Delimited 形式のファイルでは,各項目が可変数の文字を取り,それぞれの文字項目(英数字または文字)が DELIMITER 文字で囲まれ,項目間は SEPARATOR で区切られます。Delimited 形式ファイルでは,DELIMITER と SEPARATOR を指定しなければなりません。Fixed 形式ファイルでは指定する必要はありません。

CHARSET

使用する言語ドライバの名前を指定します。

DELIMITER

各文字フィールド(英数字または文字)を囲む半角の文字を一文字指定します。
FILETYPE が Delimited の時に指定します。

SEPARATOR

各項目を区切る半角の文字を一文字指定します。
FILETYPE が Delimited の時に指定します。

Field ( = 項目名, データ型, 文字数(単位数), 小数点以下桁数, 開始位置 )

残りの行は,テーブルの項目 (列) の属性を指定します。各行は「FieldX = 」で始まります。ここで X は項目番号です (Field1,Field2 など)。その次に,以下のものを指定するカンマで区切ったリストが続きます。

項目名

Paradox の項目名と同じ制限を受けます。

データ型

項目のデータ型。以下を参照してください。

    CHAR          文字
    FLOAT         64 ビット浮動小数点数
    NUMBER        16 ビット整数
    BOOL          論理値 (T または F)
    LONGINT       32 ビット倍長整数
    DATE          日付型項目。
    TIME          時刻型項目。
    TIMESTAMP     日付+時刻型項目。
    ※ メモ:日付と時刻の形式は,BDEAdministrator で指定できます。

文字数 または 単位数

文字型の場合は最大文字数を指定します。
数値型の場合 20 以下でなければなりません。
日付/時刻データ型の最大文字総数を指定します。( / や : などを含む)

小数点以下の桁数

データ型が FLOAT 型以外の場合は 0 を指定します。

開始位置

項目が開始する位置を示す,行の先頭から(先頭は 0)の文字数です。
Fixed 形式だけに使用します。

以下は,Delimited 形式と Fiexed 形式 のスキーマファイルと,それに対応したテキストファイルの例です。
尚,オンラインヘルに掲載されているスキーマファイルの例では,項目の開始位置の指定が誤っていますので参考にされる方はご注意ください。

例 1: Delimited 形式ファイル(カンマ付きテキスト)

CUSTOMER.SCH の内容

[CUSTOMER]
Filetype=Delimited
Delimiter="
Separator=,
CharSet=ascii
Field1=Customer No,Float,20,04,00
Field2=Name,Char,30,00,20
Field3=Phone,Char,15,00,50
Field4=First Contact,Date,8,00,65

CUSTOMER.TXT の内容

1221.0000,"Kauai Dive Shoppe","808-555-0269",94/04/03
1231.0000,"Unisco","809-555-3915",94/02/28
1351.0000,"Sight Diver","357-6-876708",94/04/12
1354.0000,"Cayman Divers World Unlimited","809-555-8576",94/04/17
1356.0000,"Tom Sawyer Diving Centre","809-555-7281",94/04/20

※文字項目(Char 項目)は, Delimiter で囲みます。
※項目間は,Separator で区切ります。
※日付は,BDEAdministrator で設定されている形式にしてください。

例 2: Fixed 形式ファイル(固定長テキスト)

CUSTOMER.SCH の内容

[CUSTOMER]
Filetype=Fixed
CharSet=ascii
Field1=Customer No,Float,20,04,00
Field2=Name,Char,30,00,20
Field3=Phone,Char,15,00,50
Field4=First Contact,Date,08,00,65

CUSTOMER.TXT の内容

           1221.0000Kauai Dive Shoppe             808-555-0269   94/04/03
           1231.0000Unisco                        809-555-3915   94/02/28
           1351.0000Sight Diver                   357-6-876708   94/04/12
           1354.0000Cayman Divers World Unlimited 809-555-8576   94/04/17
           1356.0000Tom Sawyer Diving Centre      809-555-7281   94/04/20
  • 桁数は,スキーマファイルの FieldX の文字数の項目で指定した長さに合せ,足りない場合は項目ごとにスペースを埋めて桁合わせしてください。
  • 日付は,BDEAdministrator で設定されている形式にしてください。

    16Bit BDE 用 TablePack コンポーネント

該当するバージョン:Delphi 1.0

Delphi1.0 用の Table 再構築用のコンポーネントです。
以下のコードを入力し,Delphi1.0 に登録することにより開発するプログラム中で使用することが出来ます。

対応する Table は dBASE / Paradox です。

unit TablPack;

interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Forms, Dialogs, DB, DBTables, DbiTypes, DbiProcs, DbiErrs;

type
  { Exceptions for TablePack }
  EPackError = class(Exception);
  EPack_InvalidParam = class(EPackError);
  EPack_InvalidHndl = class(EPackError);
  EPack_InvalidDBSpec = class(EPackError);
  EPack_NoConfigFile = class(EPackError);
  EPack_NoSuchTable = class(EPackError);
  EPack_NotSupported = class(EPackError);
  EPack_UnknownTblType = class(EPackError);
  EPack_UnknownDB = class(EPackError);
  EPack_NeedExclAccess = class(EPackError);
  EPack_IncorrectTblType = class(EPackError);
  EPack_DBLimit = class(EPackError);

  TTablePack = class(TTable)
  private
    { Private declarations }
    function GetTableType: PChar;
    procedure PackDBaseTable;
    procedure PackParadoxTable;
  protected
    { Protected declarations }
    function Chk(rslt: DbiResult): DbiResult; virtual;
  public
    { Public declarations }
    procedure Pack;
  published
    { Published declarations }
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Data Access', [TTablePack]);
end;

function TTablePack.GetTableType: PChar;
var
  { FCurProp Holds information about the structure of the table }
  FCurProp: CurProps;

begin
  { Find out what type of table is currently opened.  NOTE: This is
    different than TTablePack.TableType }
  Chk(DbiGetCursorProps(Handle, FCurProp));
  GetTableType := FCurProp.szTableType;
end;

procedure TTablePack.Pack;
var
  TType: array[0..40] of char;

begin
  { The table must be opened to get directory information about the table
    before closing }
  if Active <> True then
    raise EPackError.Create('Table must be opened to be packed');
  { Get the type of table }
  strcopy(TType, GetTableType);
  if strcomp(TType, szParadox) = 0 then
    { Call PackParadoxTable procedure if PARADOX table }
    PackParadoxTable
  else
    if strcomp(TType, szDBase) = 0 then
      { Call PackDBaseTable procedure if dBase table }
      PackDBaseTable
    else
      { PARADOX and dBase table are the only types that can be packed }
      raise EPack_IncorrectTblType.Create('Incorrect table type: ' +
                                          StrPas(TType));
end;

procedure TTablePack.PackParadoxTable;

var
  { Specific information about the table structure, indexes, etc. }
  TblDesc: CRTblDesc;
  { Uses as a handle to the database }
  hDb: hDbiDb;
  { Path to the currently opened table }
  TablePath: array[0..dbiMaxPathLen] of char;

begin
  { Initialize the table descriptor }
  FillChar(TblDesc, SizeOf(CRTblDesc), 0);
  with TblDesc do
  begin
    { Place the table name in descriptor }
    StrPCopy(szTblName, TableName);
    { Place the table type in descriptor }
    StrCopy(szTblType, GetTableType);
    { Set the packing option to true }
    bPack := True;
  end;
  { Initialize the DB handle }
  hDb := nil;
  { Get the current table's directory.  This is why the table MUST be
    opened until now }
  Chk(DbiGetDirectory(DBHandle, True, TablePath));
  { Close the table }
  Close;
  { NOW: since the DbiDoRestructure call needs a valid DB handle BUT the
    table cannot be opened, call DbiOpenDatabase to get a valid handle.
    Just leaving Active = FALSE does not give you a valid handle }
  Chk(DbiOpenDatabase(nil, 'STANDARD', dbiReadWrite, dbiOpenExcl, nil,
                        0, nil, nil, hDb));
  { Set the table's directory to the old directory }
  Chk(DbiSetDirectory(hDb, TablePath));
  { Pack the PARADOX table }
  Chk(DbiDoRestructure(hDb, 1, @TblDesc, nil, nil, nil, FALSE));
  { Close the temporary database handle }
  Chk(DbiCloseDatabase(hDb));
  { Re-Open the table }
  Open;
end;

procedure TTablePack.PackDBaseTable;
begin
  { Pack the dBase Table }
  Chk(DbiPackTable(DBHandle, Handle, nil, nil, True));
end;

function TTablePack.Chk(rslt: DbiResult): DbiResult;
var
  ErrInfo: DbiErrInfo;
  ErrStr: string;
  pErr: array[0..dbiMaxMsgLen] of char;

begin
  { Only enter the error routine if an error has occured }
  if rslt <> dbiErr_None then
  begin
    { Get information on the error that occured.  ALWAYS DO THIS FIRST!! }
    DbiGetErrorInfo(False, ErrInfo);
    if ErrInfo.iError = rslt then
    begin
      ErrStr := Format('%s  ', [ErrInfo.szErrCode]);
      if StrComp(ErrInfo.szContext[1], '') = 0 then
        ErrStr := Format('%s  %s', [ErrStr, ErrInfo.szContext[1]]);
      if StrComp(ErrInfo.szContext[2], '') = 0 then
        ErrStr := Format('%s  %s', [ErrStr, ErrInfo.szContext[2]]);
      if StrComp(ErrInfo.szContext[3], '') = 0 then
        ErrStr := Format('%s  %s', [ErrStr, ErrInfo.szContext[3]]);
      if StrComp(ErrInfo.szContext[4], '') = 0 then
        ErrStr := Format('%s  %s', [ErrStr, ErrInfo.szContext[4]]);
    end
    else
    begin
      DbiGetErrorString(rslt, pErr);
      ErrStr := StrPas(pErr);
    end;
    ErrStr := Format('Table Pack Error: %d.  %s', [rslt, ErrStr]);

    MessageBeep(mb_IconExclamation);
    { Raise the corrisponding exception }
    case rslt of
      dbiErr_InvalidParam:
        raise EPack_InvalidParam.Create(ErrStr);
      dbiErr_InvalidHndl:
        raise EPack_InvalidHndl.Create(ErrStr);
      dbiErr_InvalidDBSpec:
        raise EPack_InvalidDBSpec.Create(ErrStr);

      dbiErr_NoSuchTable:
        raise EPack_NoSuchTable.Create(ErrStr);
      dbiErr_NoConfigFile:
        raise EPack_NoConfigFile.Create(ErrStr);
      dbiErr_NotSupported:
        raise EPack_NotSupported.Create(ErrStr);
      dbiErr_UnknownTblType:
        raise EPack_UnknownTblType.Create(ErrStr);
      dbiErr_UnknownDB:
        raise EPack_UnknownDB.Create(ErrStr);
      dbiErr_NeedExclAccess:
        raise EPack_NeedExclAccess.Create(ErrStr);
      dbiErr_DBLimit:
        raise EPack_DBLimit.Create(ErrStr);
      else
        raise EPackError.Create(ErrStr);
    end;
  end;
end;

end.

    DBGrid で選択した複数行の内容を調べる方法

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
DBGrid で Options プロパティに dgMultiSelect を指定したときに,選択した複数行にアクセスするにはどうしたらいいのでしょうか?

A:
DBGrid の SelectedRows プロパティは,選択された複数行のブックマークのリストを保持しています。選択された複数のレコードには,このブックマークを経由してアクセスします。SelectedRows は,TBookmarkList オブジェクトです。TBookmarkList には Count プロパティがあり,リスト内のブックマークの数を示します。リスト内のブックマークにアクセスするには,TBookmark 配列である,Items プロパティを使用します。データセットの Bookmark を Items の要素に設定します。
以下の例では,DBGrid で選択された複数のレコードのあるフィールドを,繰り返しメッセージウィンドウに表示しています。

var
  i : integer;
  TempBookmark : TBookMark;
begin

  Table1.DisableControls;

{ 1 行も選択されていない場合には処理を終了します。}
  if DBGrid1.SelectedRows.Count > 0 then
    TempBookmark := Table1.GetBookmark  { 現在のブックマークを保管します }
  else
    Exit;

{ SelectedRows.Count -1 まで値を取り出します。 }
  for i := 0 to DBGrid1.SelectedRows.Count - 1 do
  begin
    if DBGrid1.SelectedRows.IndexOf(DBGrid1.SelectedRows.Items[i]) > -1 then
    begin
      Table1.Bookmark := DBGrid1.SelectedRows.Items[i];
      ShowMessage(Table1.Fields[1].AsString);
    end;
  end;

{ ブックマークを戻します }
  Table1.GotoBookmark(TempBookmark);
  Table1.FreeBookmark(TempBookmark);

  Table1.EnableControls;

end;

    データベースフィールドにヌル値を設定する方法

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
データベースフィールドにヌル値を設定するにはどうすればよいでしょうか?

A:
データベースフィールドにヌル値を設定するには,Clear メソッドを用いるか,以下のように引数に nil を指定して SetData メソッドを使用ます。ヌル値を禁止しているフィールドへのヌル代入は,変更をポストした時点でエラーになり,例外が生成されます。

procedure TForm1.Button1Click(Sender: TObject);
begin
  Table1.Edit;
  Table1.FieldByName('AMOUNT').SetData(nil);
  Table1.Post;
end;

    エリアス名からパス名を取得する方法

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
エリアス名からパス名を取得できますか?

A:
TSession の GetAliasParams メソッドを使用し,エリアス情報が取得できます。
ここからパス名を取得するには,以下のように行うことができます。
ユニットの uses 節に DBTables が追加されている場合には Session 変数 を利用できます。

   procedure TForm1.Button1Click(Sender: TObject);
   var
      ALIAS_LIST: TStringList;
   begin
      ALIAS_LIST := TStringList.create;
      Session.GetAliasParams('DBDEMOS',ALIAS_LIST);
      ShowMessage(ALIAS_LIST.Values['PATH']);
      ALIAS_LIST.Free;
  end;

    データベースに64K以上のサイズのイメージを登録する方法

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
データベースに64K以上のサイズのイメージを登録するにはどのように行えばよいのでしょうか?

A:
通常のイメージであれば Graphic 項目を利用することも出来ますが, 64K以上のイメージを扱うには BLOB 項目を利用する必要があります。

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      table1.Edit;
      MyBLOBField.SetData(nil);
      MyBLOBField.LoadFromFile(SourceFileName);
      table1.post;
    end;

また,登録されたイメージをファイルに取り出すには,SaveToFileメソッドを使用し, ファイルに出力します。
さらに,取り出したイメージを編集するような場合には,以下のようにストリームを使用します。

    procedure TForm1.Button2Click(Sender: TObject);
    var
      BITMAPWK: TBlobStream;
    begin
      table1.Open;
      BITMAPWK := TBlobStream.Create(MyBlobField,bmRead);
      image1.Picture.Bitmap.LoadFromStream(BITMAPWK);
      table1.close;
    end;

    BLOB 項目から JPEG イメージを読み書きするには

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
BLOB 項目から JPEG イメージを読み書きしたいのですが

A:
TBlobStream オブジェクトを使ってアクセスします。
BLOB ストリームを使うには,まず TBlobStream のインスタンスを作成して,LoadFromStream や SaveToStream メソッドで読み書きします。

uses
  JPEG;
   :
   :
// BLOB 項目に保存する例
procedure TForm1.Button1Click(Sender: TObject);
var
  JPG:  TJPEGImage;
  Strm: TBlobStream;
begin
  JPG := TJPEGImage.Create;
  JPG.LoadFromFile('c:\test.jpg');

  Table1.Edit;
  Table1.Insert;

  { BLOB ストリームを作成 }
  Strm := TBlobStream.Create(TBlobField(Table1.FieldByName('JPGIMG')), bmWrite);
  try
    { JPEG データをストリームに保存 }
    JPG.SaveToStream(Strm);
    Table1.Post;
  finally
    Strm.Free;
    JPG.Free;
  end;
end;

// BLOB 項目から読み込む例
procedure TForm1.Button2Click(Sender: TObject);
var
  JPG:  TJPEGImage;
  Strm: TBlobStream;
begin
  JPG := TJPEGImage.Create;

  { BLOB ストリームを作成 }
  Strm := TBlobStream.Create(TBlobField(Table1.FieldByName('JPGIMG')), bmRead);
  try
    { JPEG データをストリームから読み込み }
    JPG.LoadFromStream(Strm);
    { Image コンポーネントに表示}
    Image1.Picture.Assign(JPG);
  finally
    Strm.Free;
    JPG.Free;
  end;
end;

    DBCtrlGrid で選択中のパネルの色を変更するには

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
DBCtrlGrid で,現在選択されているパネルの色を変更するにはどうしたらよいでしょうか。

A:
DBCtrlGrid の OnPaintPanel イベントで処理します。
下記のサンプルを実行する前に,DBCtrlGrid 上に配置した Label の Transparentプロパティを True に設定し,背景を透過にしておきます。
尚,Transparent を True にすると False の場合より時間がかかりますので,複雑なイメージなどを処理する場合は,Color プロパティを変更するようにして下さい。

procedure TForm1.DBCtrlGrid1PaintPanel(DBCtrlGrid: TDBCtrlGrid;
  Index: Integer);
begin
  with DBCtrlGrid1 do
  begin
    if Index = PanelIndex then begin
      // フォーカスがある時のパネルの描画
      Canvas.Brush.Color := clHighlight;
      Canvas.Rectangle(0,0, PanelWidth, PanelHeight);
      // パネル上のラベルの色を変更
      Label1.Font.Color := clHighlightText;
      Label2.Font.Color := clHighlightText;
      // ブラシの色を元に戻す
      Canvas.Brush.Color := Color;
    end
    else begin
      // フォーカスがない時のラベルの色を元に戻す
      Label1.Font.Color := clBlack;
      Label2.Font.Color := clBlack;
    end;
  end;
end;

    DBGrid をダブルクリックして表示データを並べ替えたい (1998/09/04)

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
DBGrid のタイトル行をダブルクリックして,表示データの並べ替えをすることはできますか?

A:
データセットコンポーネントとして TTable を使用している場合は,IndexFieldNamesを切り替えることで,並び順を変えることができます。
タイトル行をクリックしたかどうかを調べるために,MouseToCellメソッドを用いますが,DBGrid ではプロテクトメソッドなので,TDrawGrid にキャストして使用します。
次が,DBGrid の OnDblClick イベントに記述するコードです。この例では,インデックスが存在しない項目のタイトルをクリックすると,例外が生成されます。

procedure TForm1.DBGrid1DblClick(Sender: TObject);
var
  dwPos: DWORD;
  Pos: TPoint;
  ACol, ARow: Longint;
begin
  { イベントが発生したマウスカーソルの位置を取得 }
  dwPos := GetMessagePos;
  Pos := DBGrid1.ScreenToClient(Point(LoWORD(dwPos), HiWORD(dwPos)));
  { MouseToCell を使うために DBGrid を TDrawGrid にキャストします }
  TDrawGrid(DBGrid1).MouseToCell(Pos.X, Pos.Y, ACol, ARow);
  { 最初の行の場合だけインデックスを変更 }
  if ARow = 0 then
    Table1.IndexFieldNames
     := DBGrid1.Fields[ACol-1].FieldName;
end;

    Delphiから現在のBDEのシステム状態を取得したいのですが・・・ (99/01/08)

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
Delphiから現在のBDEのシステム状態を取得したいのですが方法はありますか?

A:
BDE APIのDbiGetSysInfoを使用し取得する事が可能です。下の例を参考にしてください。
また,同様の方法で,DbiGetSysVersionを使用することによりバージョン情報や,DbiGetSysConfigを使用する事によりシステム環境設定情報などの取得もできます。

*BDE APIの詳細に関しては,BDE APIヘルプをご覧ください。

    implementation

    {$R *.DFM}
    uses dbierrs,dbiprocs,dbitypes;

    procedure TForm1.LogDbiSysinfo;
    var
       Info : SysInfo;
    begin
       DbiGetSysInfo(Info);
       with TStringList.Create do
           try
               Clear;
               Add( Format('BUFFER SPACE : %d',[Info.iBufferSpace]));
               Add( Format('HEAP SPACE   : %d',[Info.iHeapSpace]));
               Add( Format('DRIVERS      : %d',[Info.iDrivers]));
               Add( Format('CLIENTS      : %d',[Info.iClients]));
               Add( Format('SESSIONS     : %d',[Info.iSessions]));
               Add( Format('DATABASES    : %d',[Info.iDatabases]));
               Add( Format('CURSORS      : %d',[Info.iCursors]));
               SavetoFile('c:\TEMP\logcurs.txt');
           finally
               free;
           end;
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    begin
       table1.Open;
       table2.Open;
       table3.Open;
       logdbisysinfo;
       table1.Close;
       table2.Close;
       table3.Close;
    end;

    ====出力結果====
    BUFFER SPACE : 32
    HEAP SPACE   : 64
    DRIVERS      : 3
    CLIENTS      : 3
    SESSIONS     : 1
    DATABASES    : 2
    CURSORS      : 0

    テーブルのメモ型項目を1行ずつ処理したい (99/01/08)

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
テーブルのメモ型項目を1行ずつ処理したいのですが,TMemoFiled クラスには 行の概念がないようです。 どうしたらいいでしょうか?

A:
TStringList クラスを使います。 以下のサンプルでは,カレントレコードの メモ型項目の各行の先頭に行番号を追加しています。

    unit Unit1;

    interface

    uses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      StdCtrls, DBCtrls, Grids, DBGrids, Db, DBTables;

    type
      TForm1 = class(TForm)
        DataSource1: TDataSource; 
        Table1: TTable;
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
      private
        { Private 宣言 }
      public
        { Public 宣言 }
      end;

    var
      Form1: TForm1;

    implementation

    {$R *.DFM}

    procedure TForm1.Button1Click(Sender: TObject);
    var
      sl: TStringList;
      n: Integer;
    begin
      sl := TStringList.Create;
      sl.Text := Table1.FieldByName('Notes').AsString;
      for n := 0 To sl.Count-1 do
        sl[n] := Format('%4d: %s',[n+1,sl[n]]);
      Table1.Edit;
      Table1.FieldByName('Notes').AsString := sl.Text;
      Table1.Post;
      sl.Free;
    end;

    end.

    AVIデータをデータベースに登録したり再生したりするには (99/01/08)

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
AVI データをデーターベースに登録したり,登録されたデータを再生するにはどうすればいいのでしょうか?

A:
AVI データを BLOB 項目として登録します。 簡単な方法としては,テンポラリファイルを使って BLOB 項目を読み書きするといいでしょう。

以下のサンプルは, AVI データを BLOB 項目に登録して,メディアプレイヤーで再生しています。

     var
       FileName : string;

     {$IFNDEF WIN32}
       const MAX_PATH = 144;
     {$ENDIF}
     var
      {$IFDEF WIN32}
       lpPathBuffer : PChar;
      {$ENDIF}
       lpbuffer : PChar;
     begin
       { テンポラリファイルのファイル名取得 }
       GetMem(lpBuffer, MAX_PATH);
      {$IFDEF WIN32}
       GetMem(lpPathBuffer, MAX_PATH);
       GetTempPath(MAX_PATH, lpPathBuffer);
       GetTempFileName(lpPathBuffer,
                       'tmp',
                       0,
                       lpBuffer);
       FreeMem(lpPathBuffer, MAX_PATH);
      {$ELSE}
       GetTempFileName(GetTempDrive('C'),
                       'tmp',
                       0,
                       lpBuffer);
      {$ENDIF}
       result := StrPas(lpBuffer);
       FreeMem(lpBuffer, MAX_PATH);
     end;

     { AVI ファイルを BLOB 項目に読み込む }
     procedure TForm1.Button1Click(Sender: TObject);
     var
       FileStream: TFileStream;
       BlobStream: TBlobStream;
     begin
       Application.ProcessMessages;
       Button1.Enabled := false;
       Button2.Enabled := false;
       FileStream := TFileStream.Create(
         'C:\PROGRA~1\BORLAND\DELPHI~1\DEMOS\COOLSTUF\COOL.AVI',
         fmOpenRead);
       Table1.Edit;
       BlobStream := TBlobStream.Create(Table1AVI, bmReadWrite);
       BlobStream.Seek(0, soFromBeginning);
       BlobStream.Truncate;
       BlobStream.CopyFrom(FileStream, FileStream.Size);
       FileStream.Free;
       BlobStream.Free;
       Table1.Post;
       Button1.Enabled := true;
       Button2.Enabled := true;
     end;

     { BLOB 項目から AVI ファイルを読み込み,メディアプレイヤーで実行する }
     procedure TForm1.Button2Click(Sender: TObject);
     var
       FileStream: TFileStream; {a temp file}
       BlobStream: TBlobStream; {the AVI Blob}
     begin
      {Create a blob stream for the AVI blob}
       BlobStream := TBlobStream.Create(Table1AVI, bmRead);
       if BlobStream.Size = 0 then begin
        BlobStream.Free;
        Exit;
       end;
       MediaPlayer1.Close;
       MediaPlayer1.FileName := '';
       MediaPlayer1.Display := Panel1;
       Panel1.Refresh;
       if FileName <> '' then
         DeleteFile(FileName);
       FileName := GetTemporaryFileName;
       FileStream := TFileStream.Create(FileName,
                                         fmCreate or fmOpenWrite);
       FileStream.CopyFrom(BlobStream, BlobStream.Size);
       FileStream.Free;
       BlobStream.Free;
       MediaPlayer1.FileName := filename;
       MediaPlayer1.DeviceType := dtAviVideo;
       MediaPlayer1.Open;
       MediaPlayer1.Play;
     end;

     procedure TForm1.FormDestroy(Sender: TObject);
     begin
       MediaPlayer1.Close;
       MediaPlayer1.FileName := '';  
       if FileName <> '' then
         DeleteFile(FileName);
     end;

    データセットを日付でフィルタリングしたい (99/03/04)

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
TTable や TQuery でフィルタ機能を使ってデータを絞り込みたいのですが,日付項目は期待どうりの結果になりません。 日付項目は使えないのでしょうか?

A:
日付項目を使う場合には以下の二つの注意点が必要です。

  • 文字列のようにシングルコーテションで括る
  • 年の部分を4桁で指定する

例)

    DateColumn > '1999/1/1'