Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2007年09月09日] [更新 2017年02月04日] Delphi サンプルプログラム集
   
630_ADO で JET データベースの新規作成と最適化
動作確認等 Windows 7 U64(SP1) + Delphi XE(UP1) Pro + msadox.dll 6.1.7600.16385
630_CreateMDB.zip [2,990 KB] 2017年02月04日版(EXE同梱)



  • 2008年12月01日
  • デーベースの新規作成と最適化のプログラムを別々にした
  • 2010年05月30日
  • JET データベースのインデックスを取得するサンプルを追加
  • Delphi 2010(UP5) で動作確認と記事の修正等
  • 2011年05月13日
  • データベースの表名の変更のサンプルとパスワード関係の記事を追加
  • 2017年02月04日
  • 最適化とインデックス取得に Access 2007/2010 用 JET の処理コードを追加





ADO で JET データベースの新規作成と最適化 - ADOX と JRO


JET データベースは面倒なインストール作業等が必要ありません.可搬型のデータベースとして使用可能です.パーソナルなデータベースとしての利用価値はあるでしょう.そんな時の参考コードです.
JET データベースエンジンは,特にインデックスを作成しなくても,そこそこのパフォーマンスが得られるようですが,一般的に,データベースはインデックスがないとクエリー等の実行に十分なパフォーマンスが得られません.インデックスは SQL 文で操作可能です.

このページのサンプルでは,[タイプライブラリの取り込み] で ADOX_TLB.pas と JRO_TLB.pas というファイルを作成して,ADOX オブジェクトを使用しています.この作業をしなくても動作可能なプログラムは作成できますが,各オブジェクトを OleVariant で扱うことになります.OleVariant では Delphi の特徴である入力支援機能等が利用できません.入力支援機能が利用できればメソッド類の動作の目安ともなります.


以下は,サンプルプログラム集の ADO 関係の記事へのリンクです.



  • 図1
  • ADOX_TLB.pas の作成
  • これは Windows 7 U64 の場合.2.8 でも動作確認済み
  • 本サンプルでは [コンポーネントラッパーの作成] は不要.ユニットだけ作成すればよい

  • 図2
  • JRO_TLB.pas の作成
  • 本サンプルでは [コンポーネントラッパーの作成] は不要.ユニットだけ作成すればよい




01_JET データベースの新規作成


JET データベースのファイルである mdb ファイルを新規に作成して,項目が 3 つだけの表を1つ,インデックス付きで作成します.作成後にその表を表示します.既に作成済みの場合は,単にその表を表示するだけです.



図3
設計時画面
  • 以下のコンポーネントを配置 (各 1)
    TButton
    TADOConnection
    TADOQuery
    TDataSource
    TDBGrid (予めカラムを 3 つ作成)
図4
実行時画面
  • .mdb ファイルがあったら手動で削除してから実行
  • 作成直後の表は空
  • TDBGrid に入力しているところ
図5
作成されたデータベースファイル

リスト1
JET データベースファイルの新規作成
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Grids, DBGrids, DB, ADODB, Buttons, ExtCtrls, ADOX_TLB;

type
  TForm1 = class(TForm)
    DBGrid1: TDBGrid;
    Panel1: TPanel;
    btnCreate: TButton;
    ADOConnection1: TADOConnection;
    ADOQuery1: TADOQuery;
    DataSource1: TDataSource;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure btnCreateClick(Sender: TObject);
  private
    { Private 宣言 }
    FDatabaseName : String;
    function MakeConnectString(DBName, APass: String): String;
    function CreateTable : Boolean;
    procedure OpenJETDBTable;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses
  ComObj;

{$R *.dfm}

//=============================================================================
//  データベース切断
//=============================================================================
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  ADOConnection1.Connected := False;
end;

//=============================================================================
//  JETデータベースが存在して表があればそれを開いてDBGridに表示
//  なければデータベースと表を作成してから開く
//
//  オブジェクト・インスペクタの設定は以下の通り
//  ADOConnection1  デフォルトのまま
//  ADOQuery1       Connection := ADOConnection1;
//  DataSource1     DataSet    := ADOQuery1;
//  DBGrid1         DataSource := DataSource1;
//=============================================================================
procedure TForm1.btnCreateClick(Sender: TObject);
var
  LUserName    : String;
  LPassWord    : String;
  LTableList   : TStringList;
  LConnectStr  : String;
  LJET_Catalog : ADOX_TLB.Catalog;
begin
  btnCreate.Enabled := False;

  //ユーザ名とパスワード
  LUserName := 'Mr.XRAY';
  LPassWord := '123';

  //データベース名
  //作成するデータベース(ファイル)名はTEST.mdbとする
  //場所はこのプロジェクトのルート
  FDatabaseName := '..\TEST.mdb';

  //既にデータベースのファイルがある場合
  if FileExists(FDatabaseName) then begin
    ADOConnection1.Connected   := False;
    ADOConnection1.Mode        := cmReadWrite;
    ADOConnection1.LoginPrompt := False;

    //接続文字列を作成して接続
    LConnectStr                     := MakeConnectString(FDatabaseName, LPassWord);
    ADOConnection1.ConnectionString := LConnectStr;
    ADOConnection1.Connected        := True;

    LTableList := TStringList.Create;
    try
      //表の名前はPETSONとする
      //表の一覧をTableListに取得
      ADOConnection1.GetTableNames(LTableList);
      //表がなければ作成して開く
      if LTableList.IndexOf('PERSON') >= 0 then begin
        OpenJETDBTable;
      end else begin
        if CreateTable then OpenJETDBTable;
      end;
    finally
      FreeAndNil(LTableList);
    end;

  //データベースが存在しない場合は新規作成
  end else begin
    //ADOXのCatalogオブジェクトを生成
    LJET_Catalog := ADOX_TLB.CoCatalog.Create;
    try
      ADOConnection1.Connected   := False;
      ADOConnection1.Mode        := cmReadWrite;
      ADOConnection1.LoginPrompt := False;

      //接続文字列
      LConnectStr := MakeConnectString(FDatabaseName,LPassWord);

      //データベース作成
      LJET_Catalog.Create(LConnectStr);

      //接続文字列を設定して接続
      ADOConnection1.ConnectionString := LConnectStr;
      ADOConnection1.Connected        := True;

      //表を作成して開く
      if CreateTable then OpenJETDBTable;
    finally
      LJET_Catalog := nil;
    end;
  end;

  btnCreate.Enabled := True;
end;

//=============================================================================
//  接続用の文字列を生成
//  パスワードなしのMDBにも使用可能(パスワードの文字列を空文字にする)
//  ユーザ名の設定は無効なので設定していない
//
//  以下の順
//  プロバイダ
//  データベース名
//  パスワードが必要な場合の設定
//  パスワード
//=============================================================================
function TForm1.MakeConnectString(DBName, APass: String): String;
begin
  Result := 'Provider=Microsoft.Jet.OLEDB.4.0'
          + ';Data Source=' + DBName
          + ';Jet OLEDB:Database '
          + 'Password=' + APass;
end;

//=============================================================================
//  PERSONという名前の表を作成
//  同名の表があれば削除して新規に作成
//=============================================================================
function TForm1.CreateTable : Boolean;
var
  LTableList : TStringList;
begin
  Result := False;

  LTableList := TStringList.Create;
  try
    //トランザクション開始
    ADOConnection1.BeginTrans;
    try
      ADOQuery1.Close;

      ADOConnection1.GetTableNames(LTableList);
      //表は既にあるのでその表を削除
      if LTableList.IndexOf('PERSON') >= 0 then begin
        ADOQuery1.SQL.Clear;
        ADOQuery1.SQL.Add ('DROP TABLE PERSON ');
        ADOQuery1.ExecSQL;
      end;

      //表作成.項目IDをPrimaryインデックスとする
      ADOQuery1.SQL.Clear;
      ADOQuery1.SQL.Add ('CREATE TABLE PERSON ');
      ADOQuery1.SQL.Add ('( ');
      ADOQuery1.SQL.Add (' ID      INT CONSTRAINT IDX_NO PRIMARY KEY, ');
      ADOQuery1.SQL.Add (' SHIMEI  VARCHAR, ');
      ADOQuery1.SQL.Add (' ADDRESS VARCHAR ');
      ADOQuery1.SQL.Add (') ');
      ADOQuery1.ExecSQL;

      //項目SHIMEIにインデックスを作成
      ADOQuery1.SQL.Clear;
      ADOQuery1.SQL.Add ('CREATE INDEX IDX_SHIMEI ON PERSON ');
      ADOQuery1.SQL.Add (' (SHIMEI) ');
      ADOQuery1.ExecSQL;

      //コミット
      ADOConnection1.CommitTrans;
      Result := True;
    except
      //失敗したら元に戻す(ロールバック)
      ADOConnection1.RollbackTrans;
      MessageDlg('表の作成に失敗しました.', mtWarning, [mbOK], 0);
    end;
  finally
    FreeAndNil(LTableList);
  end;
end;

//=============================================================================
//  表を開くクエリーを実行
//  DBGrid1にはあらかじめカラムを作成しておく
//=============================================================================
procedure TForm1.OpenJETDBTable;
begin
  ADOQuery1.DisableControls;

  ADOQuery1.Close;
  ADOQuery1.SQL.Clear;
  ADOQuery1.SQL.Add('SELECT ID, SHIMEI, ADDRESS FROM PERSON ');
  ADOQuery1.Open;

  ADOQuery1.EnableControls;

  //DBGridへの表示を設定
  DBGrid1.Columns[0].FieldName := 'ID';
  DBGrid1.Columns[1].FieldName := 'SHIMEI';
  DBGrid1.Columns[2].FieldName := 'ADDRESS';

  DBGrid1.Columns[0].Title.Caption := 'ID';
  DBGrid1.Columns[1].Title.Caption := '氏名';
  DBGrid1.Columns[2].Title.Caption := '住所';

  DBGrid1.Columns[0].Width := 50;
  DBGrid1.Columns[1].Width := 90;
  DBGrid1.Columns[2].Width := 210;
end;

end.




02_JET データベースの最適化とパスワードの変更


JET データベースのファイルは使用しているとそのサイズが肥大化し,パフォーマンスも低下してきます.それを「最適化」します.いつどんなタイミングで最適化したらいいのかはよくわかりませんが,筆者の使用しているアプリで,起動時または終了時に最適化を選択できるものがあります.

このサンプルでは Access 98 /2000 用の JET データベースの最適化には JRO (Microsoft Jet and Replication Objects) を使用しています.Access 2007 / 2010 用の JET データベースの最適化には DAO オブジェクトの CompactDatabase メソッドを使用しています.
新しいパスワードの入力コントロールを追加すれば,パスワードの変更もできます.

また,DAO オブジェクトの CompactDatabase メソッドの第 4 引数の値を,JET エンジン 4.0 に該当する dbVersion40 にすれば,Access 2007 / 2010 用のデータベースを Access 2000 用のデータベースに変換することができます.




図6
設計時画面
  • ファイルを選択後,パスワード入力ダイアログ
  • パスワードが不要の場合は空のままとする
  • 前のサンプルの DB のパスワードは 123
図7
最適化終了

リスト2
JET データベースファイルの最適化
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Buttons, ExtCtrls, JRO_TLB;

type
  TForm1 = class(TForm)
    OpenDialog1: TOpenDialog;
    btnRefresh: TButton;
    procedure btnRefreshClick(Sender: TObject);
  private
    { Private 宣言 }
    function GetJETVersionText(ADBName: string): string;
    function MakeConnectString(ADBName, APass: String): string;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses
  DBLogDlg,
  ComObj;

{$R *.dfm}

//=============================================================================
//  JETデータベース最適化
//  元のファイルの複製を作成しそれを最適化する
//  パスワードの変更にも使用できる
//
//  LoginDilaogEx関数の使用にはusesにDBLogDlgが必要
//=============================================================================
procedure TForm1.btnRefreshClick(Sender: TObject);
const
  dbLangJapanese = ';LANGID=0x0411;CP=932;COUNTRY=0';
  dbVersion120 = 128;
  dbVersion40  = 64;
var
  LJETVerText     : string;
  LDatabaseName   : string;
  LUserName       : String;
  LPassWord       : string;
  LPassWordArg    : string;
  LPassWordNew    : string;
  LCompDBName     : string;
  LSrcConnectStr  : string;
  LDestConnectStr : string;
  LJETEngine      : JRO_TLB.JetEngine;
  LACE_JETEngine  : OleVariant;
  LResultBool     : Boolean;
begin
  OpenDialog1.Filter:= 'mdb ファイル(*.mdb)|*.mdb';

  if OpenDialog1.InitialDir='' then begin
    OpenDialog1.InitialDir := ExtractFilePath(ExtractFileDir(Application.ExeName));
  end;
  if OpenDialog1.Execute = False then exit;
  OpenDialog1.InitialDir := ExtractFileDir(OpenDialog1.FileName);
  Update;


  //最適化するデータベース名
  LDatabaseName := OpenDialog1.FileName;
  //最適化後のデータベース名
  LCompDBName := ExtractFilePath(LDatabaseName) + 'COMP.mdb';
  //もし前の作業で残っていれば削除
  DeleteFile(LCompDBName);

  //JETのバージョン文字列を取得
  LJETVerText := GetJETVersionText(LDatabaseName);
  if LJETVerText = ''  then exit;

  //ユーザ名とパスワード(ユーザ名は実際には不要)
  LUserName := 'Mr.XRAY';
  LPassWord := '';

  if LoginDialogEx('JETデータベース', LUserName, LPassWord, False) then begin
    Update;
    Screen.Cursor := crSQLWait;

    LResultBool := False;

    //JET 2000用
    if LowerCase(LJETVerText) = 'standard jet db' then begin
    //JetEngineオブジェクトを生成
      //LJETEngine := CreateComObject(CLASS_JetEngine) as IJetEngine;でも同じ
      LJETEngine := JRO_TLB.CoJetEngine.Create;
      try
        //接続文字列を作成
        LSrcConnectStr := MakeConnectString(LDatabaseName, LPassWord);
        //パスワードを変更する場合はここのLPassWordを変更する
        LDestConnectStr := MakeConnectString(LCompDBName, LPassWord);
        //最適化
        LJETEngine.CompactDatabase(LSrcConnectStr, LDestConnectStr);
        LResultBool := True;
      except
      end;
      LJETEngine := nil;

    end else
    //JET 2007/2010用
    if LowerCase(LJETVerText) = 'standard ace db' then begin
      //JetEngineオブジェクトを生成
      LACE_JETEngine := CreateOleObject('DAO.DBEngine.120');
      try
        //パスワードを変更する場合は,LPassWordNew := ';pwd=abc';のように指定する
        LPassWordNew := '';
        LPassWordArg := '';
        if LPassWord <> '' then LPassWordArg := ';pwd=' + LPassWord;
        //最適化
        LACE_JETEngine.CompactDatabase(LDatabaseName,
                                       LCompDBName,
                                       dbLangJapanese + LPassWordNew,
                                       dbVersion120,
                                       LPassWordArg);
        LResultBool := True;
      except
      end;
      LACE_JETEngine := Unassigned;
    end;

    if LResultBool then begin
      //元のmdbファイルを削除して最適化したmdbを元の名前にする
      DeleteFile(LDatabaseName);
      RenameFile(LCompDBName, LDatabaseName);
      Application.ProcessMessages;
      MessageBox(Handle, '最適化が終了しました', '情報', MB_ICONINFORMATION);
    end else begin
      //パスワードが違う場合も失敗
      MessageBox(Handle, '最適化に失敗しました', '情報', MB_ICONWARNING);
    end;
  end;

  Screen.Cursor := crDefault;
end;

//-----------------------------------------------------------------------------
//  mdbファイル内のJETバージョン文字列を取得
//-----------------------------------------------------------------------------
function TForm1.GetJETVersionText(ADBName: string): string;
var
  LFileStream : TFileStream;
  LBuffer     : array [0..15] of AnsiChar;
begin
  Result := '';
  if not FileExists(ADBName) then exit;

  //JETのバージョン文字列を取得
  LFileStream := TFileStream.Create(ADBName, fmOpenRead);
  try
    LFileStream.Position := 4;
    LFileStream.Read(LBuffer, Length(LBuffer));
    Result := Trim(string(LBuffer));
  finally
    FreeAndNil(LFileStream);
  end;
end;

//-----------------------------------------------------------------------------
//  接続用の文字列を生成
//  パスワードなしのMDBにも使用可能(パスワードの文字列を空文字にする)
//  ユーザ名の設定は無効なので設定していない
//
//  以下の順
//  プロバイダ
//  データベース名
//  パスワードが必要な場合の設定
//  パスワード
//-----------------------------------------------------------------------------
function TForm1.MakeConnectString(ADBName, APass: string): string;
begin
  Result := 'Provider=Microsoft.Jet.OLEDB.4.0'
          + ';Data Source=' + ADBName
          + ';Jet OLEDB:Database '
          + 'Password=' + APass;
end;

end.




03_JET データベースのインデックスを取得して表示


表のインデックスは SQL 文でも操作できますが,インデックスの取得機能はないようです.そこで,インデックスの一覧を表示するコードを作成してみました.ADOX_TLB.pas 内のオブジェクトを使用しています.



図8
設計時画面
図9
実行時画面
  • 前のサンプルで作成したデータベースの場合 (パスワードは 123)
  • * 印は Primary インデックスの意味
  • システム関係の表も表示されている

リスト3
JET データベースのインデックスを取得して表示
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Buttons, ExtCtrls, ADOX_TLB, ComCtrls;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    ListBox1: TListBox;
    Splitter1: TSplitter;
    ListView1: TListView;
    Button1: TButton;
    OpenDialog1: TOpenDialog;
    procedure Button1Click(Sender: TObject);
    procedure ListBox1Click(Sender: TObject);
  private
    { Private 宣言 }
    FConnectStr    : String;
    FDatabaseName : String;
    function GetJETVersionText(DBName: string): string;
    function MakeConnectString(AJETVerText, ADBName, APass: string): string;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses DBLogDlg;

{$R *.dfm}

//=============================================================================
//  JETデータベースの表名リストを作成
//
//  LoginDilaogEx関数の使用にはusesにDBLogDlgが必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LJETVerText  : string;
  LUserName    : string;
  LPassWord    : string;
  LJET_Catalog : ADOX_TLB.Catalog;
  LJET_Table   : ADOX_TLB.Table;
  i            : Integer;
begin
  OpenDialog1.Filter:='JETデータベースファイル(*.mdb)|*.mdb';

  if OpenDialog1.InitialDir='' then OpenDialog1.InitialDir:= '../';
  if OpenDialog1.Execute = False then exit;
  Update;

  ListBox1.Items.Clear;
  ListBox1.Items.BeginUpdate;

  //データベース名
  FDatabaseName := OpenDialog1.FileName;
  //JETのバージョン文字列を取得
  LJETVerText := GetJETVersionText(FDatabaseName);
  if LJETVerText = ''  then exit;


  //ユーザ名とパスワード(ユーザ名は実際には不要)
  LUserName := 'Mr.XRAY';
  LPassWord := '';

  if LoginDialogEx('JETデータベース', LUserName, LPassWord, False) then begin
    //ADOXのCatalogオブジェクトとTableオブジェクトを生成
    LJET_Catalog := ADOX_TLB.CoCatalog.Create;
    LJET_Table   := ADOX_TLB.CoTable.Create;

    //接続文字列を作成
    FConnectStr  := MakeConnectString(LJETVerText, FDatabaseName, LPassWord);

    try
      //接続してCatalogオブジェクトを取得
      LJET_Catalog.Set_ActiveConnection(FConnectStr);

      //表のリストをListBox1に表示
      for i := 0 to LJET_Catalog.Tables.Count -1  do begin
        LJET_Table := LJET_Catalog.Tables[i];
        ListBox1.Items.Add(LJET_Table.Name);
      end;
    except
      raise;
    end;
  end;

  ListBox1.Items.EndUpdate;

  LJET_Catalog := nil;
  LJET_Table   := nil;
end;

//=============================================================================
//  ListBox1のOnClickイベント処理
//  選択した表に設定されているインデックスとインデックスが定義されている項目
//  名(フィールド名)をリスト
//
//  ListView1の設定
//  ViewStyle = vsReport
//  カラムを(Columnsプロパティで)2つ作成
//=============================================================================
procedure TForm1.ListBox1Click(Sender: TObject);
var
  LJET_Catalog : ADOX_TLB.Catalog;
  LJET_Table   : ADOX_TLB.Table;
  LJET_Index   : ADOX_TLB.Index;
  LItem        : TListItem;
  i            : Integer;
  j            : Integer;
begin
  if ListBox1.SelCount = 0 then exit;

  //処理に必要なオブジェクトを生成
  LJET_Catalog := ADOX_TLB.CoCatalog.Create;
  LJET_Table   := ADOX_TLB.CoTable.Create;
  LJET_Index   := ADOX_TLB.CoIndex.Create;

  //表一覧を取得する際に作成した接続文字列ConnectStrを使用して接続
  //その際にLJET_Catalogをnilにしないで,グローバル変数にしておけばこの行と
  //CoCatalog.Createは不要
  LJET_Catalog.Set_ActiveConnection(FConnectStr);

  //ListBox1の選択した表名のTableオブジェクトを取得
  LJET_Table := LJET_Catalog.Tables[ListBox1.Items[ListBox1.ItemIndex]];

  ListView1.Items.Clear;
  ListView1.Items.BeginUpdate;

  //表に設定されているインデックスとインデックスが定義されている項目名をリスト
  for i := 0 to LJET_Table.Indexes.Count - 1 do begin
    LJET_Index := LJET_Table.Indexes[i];

    for j := 0 to LJET_Index.Columns.Count - 1 do begin
      LItem := ListView1.Items.Add;
      //PrimaryKeyの時は先頭に*を付加
      if LJET_Index.PrimaryKey then begin
        LItem.Caption := '* ' + LJET_Index.Name;
      end else begin
        LItem.Caption := LJET_Index.Name;
      end;
      LItem.SubItems.Add(LJET_Index.Columns[j].Name);
    end;
  end;
  ListView1.Items.EndUpdate;

  LJET_Catalog := nil;
  LJET_Table   := nil;
  LJET_Index   := nil;
end;

//-----------------------------------------------------------------------------
//  mdbファイル内のJETバージョン文字列を取得
//-----------------------------------------------------------------------------
function TForm1.GetJETVersionText(DBName: string): string;
var
  LFileStream : TFileStream;
  LBuffer     : array [0..15] of AnsiChar;
begin
  Result := '';
  if not FileExists(DBName) then exit;

  //JETのバージョン文字列を取得
  LFileStream := TFileStream.Create(DBName, fmOpenRead);
  try
    LFileStream.Position := 4;
    LFileStream.Read(LBuffer, Length(LBuffer));
    Result := Trim(string(LBuffer));
  finally
    FreeAndNil(LFileStream);
  end;
end;

//-----------------------------------------------------------------------------
//  接続用の文字列を生成
//  パスワードなしのMDBにも使用可能(パスワードの文字列を空文字にする)
//  ユーザ名の設定は無効なので設定していない
//
//  以下の順
//  プロバイダ
//  データベース名
//  パスワードが必要な場合の設定
//  パスワード
//
//  Microsoft Access 98/2000 のJETはMicrosoft.ACE.OLEDB.12でも接続可能
//-----------------------------------------------------------------------------
function TForm1.MakeConnectString(AJETVerText, ADBName, APass: string): string;
begin
  if LowerCase(AJETVerText) = 'standard jet db' then begin
    Result := 'Provider=Microsoft.Jet.OLEDB.4.0'
            + ';Data Source=' + ADBName
            + ';Jet OLEDB:Database '
            + 'Password=' + APass;
  end else
  if LowerCase(AJETVerText) = 'standard ace db' then begin
    Result := 'Provider=Microsoft.ACE.OLEDB.12.0'
            + ';Data Source=' + ADBName
            + ';Jet OLEDB:Database '
            + 'Password=' + APass;
  end;
end;

end.




04_JET データベースの表名を変更


JET データベースでは,表名 (テーブル名)を 変更する SQL 文は使用できません.
以下のサンプルでは,ADOX の Catalog オブジェクトの Tablesコ レクションから,対象となる表に対して,表名変更を実行します.
ここでは,本ページの最初のサンプルで作成した PERSON という表の名前を PERSON_ABC という名前に変更します.



図10
設計時画面
図11
実行時画面
  • 名前を変更した表を開いて表示

リスト4
JET データベースの表の名前を変更する例
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Grids, DBGrids, DB, ADODB, Buttons, ExtCtrls, ADOX_TLB;

type
  TForm1 = class(TForm)
    DBGrid1: TDBGrid;
    Panel1: TPanel;
    ADOConnection1: TADOConnection;
    ADOQuery1: TADOQuery;
    DataSource1: TDataSource;
    Button1: TButton;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
    FDatabaseName : String;
    function MakeConnectString(DBName, APass: String): String;
    procedure OpenJETDBTable(TableName: String);
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  データベース切断
//=============================================================================
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  ADOConnection1.Connected := False;
end;

//=============================================================================
//  テーブル名(表名)を変更する
//  TEST.mdbというデータベースが存在してPERSONという名前の表もあると仮定
//
//  ADOX_TLB.Catalogの使用にはusesにADOX_TLBが必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LBeforeTblName : String;
  LAfterTblName  : String;
  LUserName      : String;
  LPassWord      : String;
  LConnectStr    : String;
  LTableList     : TStringList;
  LJET_Catalog   : ADOX_TLB.Catalog;
begin
  //変更前と変更後の表名
  LBeforeTblName := 'PERSON';
  LAfterTblName  := 'PERSON_ABC';

  //ユーザ名とパスワード
  LUserName := 'Mr.XRAY';
  LPassWord := '123';

  //データベース名
  //開くデータベース(ファイル)名はTEST.mdb
  //場所はこのプロジェクトのフォルダの1つ上のフォルダ
  FDatabaseName := '..\TEST.mdb';
  //データベースのファイルがなければ終了
  if not FileExists(FDatabaseName) then exit;

  ADOConnection1.Connected   := False;
  ADOConnection1.Mode        := cmReadWrite;
  ADOConnection1.LoginPrompt := False;
  //接続文字列を作成
  LConnectStr                     := MakeConnectString(FDatabaseName, LPassWord);
  ADOConnection1.ConnectionString := LConnectStr;
  ADOConnection1.Connected        := True;

  //表名のリストを作成して,目的の表があるかを確認
  LTableList := TStringList.Create;
  try
    ADOConnection1.GetTableNames(LTableList);
    //変更前の表があって,変更後の表名がなければ表名の変更を実行
    if (LTableList.IndexOf(LBeforeTblName) >= 0) then begin
      if (LTableList.IndexOf(LAfterTblName) < 0) then begin

        ADOConnection1.Connected := False;
        //ADOXのCatalogオブジェクトを生成
        LJET_Catalog := ADOX_TLB.CoCatalog.Create;
        try
          //ADOXのCatalog接続(アクティブ化)
          LJET_Catalog.Set_ActiveConnection(LConnectStr);
          //テーブル名変更
          LJET_Catalog.Tables.Item[LBeforeTblName].Name := LAfterTblName;
        finally
          LJET_Catalog := nil;
        end;
      end;
    end;

    //表を開く
    if (LTableList.IndexOf(LAfterTblName) >= 0) then begin
      OpenJETDBTable(LAfterTblName);
    end;
  finally
    FreeAndNil(LTableList);
  end;
end;

//=============================================================================
//  表を開くクエリーを実行
//  DBGrid1にはあらかじめカラムを作成してあるものとする
//=============================================================================
procedure TForm1.OpenJETDBTable(TableName: String);
begin
  ADOQuery1.Close;
  ADOQuery1.SQL.Clear;
  ADOQuery1.SQL.Add('SELECT ID, SHIMEI, ADDRESS FROM ' + TableName);
  ADOQuery1.Open;

  //DBGridへの表示を設定
  DBGrid1.Columns[0].FieldName := 'ID';
  DBGrid1.Columns[1].FieldName := 'SHIMEI';
  DBGrid1.Columns[2].FieldName := 'ADDRESS';

  DBGrid1.Columns[0].Title.Caption := 'ID';
  DBGrid1.Columns[1].Title.Caption := '氏名';
  DBGrid1.Columns[2].Title.Caption := '住所';

  DBGrid1.Columns[0].Width := 50;
  DBGrid1.Columns[1].Width := 90;
  DBGrid1.Columns[2].Width := 210;
end;

//=============================================================================
//  接続用の文字列を生成
//  パスワードなしのMDBにも使用可能(パスワードの文字列を空文字にする)
//  ユーザ名の設定は無効なので設定していない
//
//  以下の順
//  プロバイダ
//  データベース名
//  パスワードが必要な場合の設定
//  パスワード
//=============================================================================
function TForm1.MakeConnectString(DBName, APass: String): String;
begin
  Result := 'Provider=Microsoft.Jet.OLEDB.4.0'
          + ';Data Source=' + DBName
          + ';Jet OLEDB:Database '
          + 'Password=' + APass;
end;

end.




05_JET データベースのパスワードを忘れたら


データベースのパスワードを忘れると,データベースを操作することができません.
そのような場合は,例えば Rixler Software の Access Password Recovery Master というユーティリティを使用すると解析できます.
ネットで検索すると,この他にもこの種のアプリケーションがあるようです.