Sign in Join
Wiki copytemporary

MS Access/ja

English · Español · Français · Русский · 日本語


データベースのポータル
参照: · Databases 概要 · ライブラリ · フィールドの型 · コントロール · FAQ · SqlDBHowto/ja · TSQLQuery の利用 · メモリ上で動作するデータベースの作り方 · チュートリアル/練習となる記事: · 概要 · 0 - データベースのセットアップ · 1 - 開始 · 2 - 編集 · 3 - クエリ · 4 - データモジュール · SQLdb Programming Reference/ja · 各種データベース · Advantage - MySQL - MSSQL - Postgres - Interbase - Firebird - Oracle - ODBC - Paradox - SQLite - dBASE - MS Access - Zeos

このページはODBCとFPCのビルトイン、SQLDBを用いてどのようにして Microsoft Access データベースを用いるか解説する。

MS Access 固有事項

プライマリキーをキーとして用いる

TSQLQuery プロパティでは、Set UsePrimaryKeyAsKey: Falseと設定しなければならないだろう

オートナンバープライマリキーを挿入させる

データを挿入した後で、Access 2000とより新しいバージョンはこのクエリを用いて、適時挿入のオートナンバープライマリキーの挿入をサポートしている:

pascal
SELECT @@IDENTITY

ODBC ドライバ

Windows

2つの異なる ODBC ドライバがMicrosoft Accessにある:

Unix/Linux

The [mdbtools project] はMS Accesssに限定的なサポートを提供している。おそらく使うことのできるODBCドライバが含まれている。Mdbtools、mdbtools-dev、mdbtools-gmdbパッケージをインストールしてみること。

少なくともDebianではODBCドライバ名は"MDBTools"である。

SQLクエリにおけるワイルドカード

Microsoft Accessは他のデータベースシステムと比較して異なったワイルドカード文法を持っている。以下の情報は "Intermediate Microsoft Jet SQL for Access 2000" [MSDN]で取得したもので、これはもはやここにはない(第3者のサイトにコピーがある)。機能するようにテストされている。

ワイルドカード文字 摘要
% (パーセント) どの文字のどの数ともマッチし、パターン文字列でどこでも使える。
_ (アンダースコア) どの1文字にもマッチし、パターン文字列でどこでも使える。
[] (角括弧) 括弧の中に含まれたリストの1文字にマッチし、パターン文字列でどこでも使える。
! (エクスクラメーション) 角括弧に含まれたリストにないどの1文字にマッチする。
- (ハイフン) 角括弧に含まれた範囲のどの文字列にもマッチする。

以下に注意

例: SELECT * FROM [Birthday Table] WHERE ([Birth date] >= #2000-01-01#)

ファイルベースのDSN 要領

ファイルDSNは単に接続設定がファイルに書かれた単純なものである。ファイルDSNを持つ理由は、もしもしデータソース接続を多くの異なるシステムのユーザーに配布したいときに、ファイルDSNは各々のシステムでDSNの設定をしなくてもするためである。 例えば、デスクトップにファイルDSNをデータベースの所在を報告するために作ったとする。そうするとユーザーにそのファイルを送ることができる。ユーザーはそのファイルDSNをハードディスクに保存しファイルDSNで示された場所を特定することができる。

ファイルベースのDSNをSQLDBドライバで使いたいときは:

ファイルDSNの設定

ファイル DSNの内部

例えば、MS Accessデータベースを参照するファイルDSNはこんな感じ になるかも しれない:

pascal
[ODBC]
    DRIVER=Microsoft Access Driver (*.mdb)
    UID=admin
    UserCommitSync=Yes
    Threads=3
    SafeTransactions=0
    PageTimeout=5
    MaxScanRows=8
    MaxBufferSize=2048
    FIL=MS Access
    DriverId=25
    DefaultDir=
    DBQ=YOUR_msaccess.mdb

ファイルベースのDSNを設定する

グリッドと他の埋め込みコントロールの使用法は他のSQLDBコネクタと同じであるので、ここでは割愛する。

ODBC接続を使うときには、TODBCConnection オブジェクトが必要である。

TOBDCConnection プロパティ:

ファイルDSN: 先に保存したDSNファイルに対するpath+ファイル名、例えばc:\mylazarus\project1\myFile.dsn Username: admin(もしくはAccessセキュリティを用いているなら何らかのユーザー名)、このパラメータはMS Accessセキュリティを用いていないならば必要ない。 他のプロパティには手を触れないこと。

システム/ユーザー DSN

ODBCで説明した通り、システム、またはユーザーDSNを用いることもでき、その場合、接続設定は保存されたファイルではなく、ODBCコントロールパネルで定義される。 TODBCConnectionは

DatabaseName: <name_of_your_DSN>

を持たなければならない。

DSNレス接続

ODBCで説明したとおり、DSNレスの接続はAccessデータベースに対するすべての接続パラメータを特定する記述することにより可能となる。それはこのようなものになるだろう:

pascal
//注意: ここでは新しいMS Accessドライバを用いている。おそらく古いものも使えるだろう:
      conn.Driver:='Microsoft Access Driver (*.mdb, *.accdb)';
      conn.Params.Add('DBQ=c:\somedirectory\test.mdb');
      ... ??????/???????????????????????????...

これはTODBCConnectionを用いたAccess mdbのテーブルに対するクエリの仕方の例である、TSQLTransaction と TSQLQuery; mdbファイルはプロジェクトのバイナリと同じフォルダにある。

pascal
procedure TForm1.Button1Click(Sender: TObject);
    begin
      //接続
      ODBCConnection1.Driver := 'Microsoft Access Driver (*.mdb, *.accdb)';
      ODBCConnection1.Params.Add('DBQ='+Application.Location+'test.mdb');      // 必要なmdbファイルの場所
      ODBCConnection1.Params.Add('Locale Identifier=1031');
      ODBCConnection1.Params.Add('ExtendedAnsiSQL=1');
      ODBCConnection1.Params.Add('CHARSET=ansi');
      ODBCConnection1.Connected := True;
      ODBCConnection1.KeepConnection := True;
         
      //トランザクション
      SQLTransaction1.DataBase := ODBCConnection1;
      SQLTransaction1.Action := caCommit;
      SQLTransaction1.Active := True;
         
      SQLQuery1.DataBase := ODBCConnection1;
      SQLQuery1.UsePrimaryKeyAsKey := False;
      SQLQuery1.SQL.Text := 'select * from Customers';
      SQLQuery1.Open;
    end;

コード例

Lazarus: フォームにデータを埋め込む

実際に動くコード例:(Updated2_with_add_delete_update) www.mediafire.com/file/ne1jx3zpnwzefq3/msaccesstest2.zip [このリンクは - 2020 11月時点では切れている]

pascal
unit Unit1; 
    
    {$mode objfpc}{$H+}
    
    interface
    
    uses
      Classes, SysUtils, odbcconn, sqldb, db, FileUtil, LResources, Forms, Controls,
      Graphics, Dialogs, DBGrids, DbCtrls, StdCtrls, Printers, PrintersDlgs;
    
    type
    
      { TForm1 }
    
      TForm1 = class(TForm)
        Button1: TButton;
        Button2: TButton;
        Button3: TButton;
        Button4: TButton;
        Datasource1: TDatasource;
        DBEdit1: TDBEdit;
        DBEdit2: TDBEdit;
        DBGrid1: TDBGrid;
        ODBCConnection1: TODBCConnection;
        PrintDialog1: TPrintDialog;
        SQLQuery1: TSQLQuery;
        SQLTransaction1: TSQLTransaction;
        procedure Button1Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
        procedure Button3Click(Sender: TObject);
        procedure Button4Click(Sender: TObject);
        procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
        procedure FormShow(Sender: TObject);
      private
        { private declarations }
        procedure PrintDbGrid(dbGrid:TdbGrid);
      public
        { public declarations }
      end; 
    
    var
      Form1: TForm1; 
    
    implementation
    
    { TForm1 }
    
    procedure TForm1.FormShow(Sender: TObject);
    begin
      //接続
      ODBCConnection1.FileDSN := ExtractFilePath(Application.ExeName) + 'file.dsn';
      ODBCConnection1.Connected := True;
      ODBCConnection1.KeepConnection := True;
    
      //トランザクション
      SQLTransaction1.DataBase := ODBCConnection1;
      SQLTransaction1.Action := caCommit;
      SQLTransaction1.Active := True; //not applied to ms access(false)
    
      SQLQuery1.DataBase := ODBCConnection1;
      SQLQuery1.UsePrimaryKeyAsKey := False;
    
      SQLQuery1.SQL.Text := 'select * from table1';
    
      // :id はフィールド名 idのパラメータ
      SQLQuery1.deleteSQL.Text := 'delete from table1 where id=:id';
      //:name はフィールド名 nameのパラメータ
      SQLQuery1.updateSQL.Text := 'update table1 set name=:name where id=:id';
    
      DataSource1.DataSet := SQLQuery1;
      DBGrid1.DataSource := DataSource1;
      DBGrid1.ReadOnly := true;
    
      DBEdit1.DataField := 'id';
      DBEdit1.DataSource := DataSource1;
      DBEdit2.DataField := 'name';
      DBEdit2.DataSource := DataSource1;
    
      SQLQuery1.Open;
    end;
    
    function MulDiv(nNumber, nNumerator, nDenominator: Integer): Integer;
    begin
      Result:=Round(int64(nNumber)*int64(nNumerator)/nDenominator);
    end;
    procedure TForm1.PrintDbGrid(dbGrid:TdbGrid);
    const
      LeftMargin = 0.05;
      TopMargin = 0.05;
      BottomMargin = 0.05;
    var
      i: integer;
      x,y: integer;
    begin
      if PrintDialog1.Execute then
        begin
        Printer.BeginDoc;
        Printer.Canvas.Font.Size := 12;
    
        y := Round(TopMargin*Printer.PageHeight);
        dbGrid.DataSource.DataSet.First;
        while not dbGrid.DataSource.DataSet.Eof do
          begin
          x := Round(LeftMargin*Printer.PageWidth);
          for i := 0 to dbGrid.DataSource.DataSet.FieldCount-1 do
            begin
            printer.Canvas.TextOut(x,y,dbGrid.DataSource.DataSet.Fields[i].AsString);
            x := x + MulDiv(dbGrid.Columns[i].Width,72, dbGrid.Width);
            end;
          dbGrid.DataSource.DataSet.Next;
          y := y + printer.Canvas.TextHeight('A');
          if y > (1-TopMargin-BottomMargin)* Printer.PageHeight then
            begin
            y := Round(TopMargin*Printer.PageHeight);
            Printer.NewPage;
            end;
          end;
        Printer.EndDoc;
        end
        else
        Form1.caption := 'NO PRINTER INSTALLED';
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      PrintDbGrid(DBGrid1);
    end;
    
    procedure TForm1.Button2Click(Sender: TObject);
    begin
    if button2.Caption = 'new' then
    begin
      SQLQuery1.Insert;
      button2.Caption := 'save';
      exit
      end
      else
      begin
        if (dbedit1.Text = '') or (dbedit2.Text = '')
        then
        begin
        SQLQuery1.Cancel;
        end
        else
        begin
        if SQLQuery1.State = dsInsert then
           begin
           SQLQuery1.Post;
           SQLQuery1.ApplyUpdates;
           Form1.caption := 'ADDED';
           end;
        end;
      end;
    button2.Caption := 'new';
    end;
    
    procedure TForm1.Button3Click(Sender: TObject);
    begin
    if SQLQuery1.RecordCount>0 then
      begin
      SQLQuery1.Delete;
      SQLQuery1.ApplyUpdates;
    
      //もしSQLdBで問題が生じたら、この2行を加える、あるいは除いてみる
      //これら2ラインはMS AccessデータベースのSQLdBのバグに対する手当である
      //**** bugtracker アイテムには見当たらない、bugtrackerを作ってほしい
      //SQLQuery1.Close;
      //SQLQuery1.Open;
    
    
      Form1.caption := 'DELETED';
      end;
    end;
    
    procedure TForm1.Button4Click(Sender: TObject);
    begin
      if SQLQuery1.RecordCount>0 then
      begin
        SQLQuery1.Edit;
        SQLQuery1.Post;
        Sqlquery1.ApplyUpdates;
        Form1.caption := 'UPDATED';
      end;
    end;
    
    procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: boolean);
    begin
      SQLQuery1.Close;
      CanClose := True;
    end;
    
    initialization
      {$I unit1.lrs}
    
    end.

プログラム的にデータベースを生成する

ODBCドライバを用い、プログラム的にMicrosoft Accessデータベースを作ることができる。以下のコードはWindowsの32-bit、64-bitで実行可能である。

コード例:

pascal
uses
      ..., sysutils, odbcsqldyn;
    
    const
       ODBC_ADD_DSN=1;
       { just for reference...
       ODBC_CONFIG_DSN=2;
       ODBC_REMOVE_DSN=3;
       ODBC_ADD_SYS_DSN=4;
       ODBC_CONFIG_SYS_DSN=5;
       ODBC_REMOVE_SYS_DSN=6;
       ODBC_REMOVE_DEFAULT_DSN=7; }
    
    function SQLConfigDataSource(hwndParent: Integer; fRequest: Integer;
      lpszDriverString: PChar; lpszAttributes: PChar): Integer; stdcall;
      external 'odbccp32.dll';
    
    function SQLInstallerError(iError: integer; pfErrorCode: PInteger;
      lpszErrorMsg: String; cbErrorMsgMax: integer; pcbErrorMsg: PInteger): integer; stdcall;
      external 'odbccp32.dll';
    
    procedure CreateAccessDatabase(DatabaseFile: string);
    var
      cmd: String;
      driver: String;
      errCode, errMsgLength: DWord;
      errMsg: String;
      retCode: integer;
      ext: String;
    begin
      ext := Lowercase(ExtractFileExt(DatabaseFile));
    
      driver := 'Microsoft Access Driver (*.mdb, *.accdb)';
      { このドライバで
        CREATE_DBV12 は .accdbフォーマットデータベースができる
        CREATE_DBV4 は.mdbフォーマットデータベースができる
        //stackoverflow.com/questions/9205633/how-do-i-specify-the-odbc-access-driver-format-when-creating-the-database
      }
      if ext = '.mdb' then
        cmd := 'CREATE_DBV4="' + DatabaseFile + '"'
      else if ext = '.accdb' then
        cmd := 'CREATE_DBV12="' + DatabaseFile + '"'
      else
        raise Exception.Create('Invalid database file extension.');
    
      retCode := SQLConfigDataSource(0, ODBC_ADD_DSN, PChar(driver), PChar(cmd));
      if not (retCode in [SQL_SUCCESS, SQL_SUCCESS_WITH_INFO]) then
      begin
        //別のドライバを試す
        driver := 'Microsoft Access Driver (*.mdb)';
        cmd := 'CREATE_DB="' + DatabaseFile + '"';
        retCode := SQLConfigDataSource(0, ODBC_ADD_DSN, PChar(driver), PChar(cmd));
      end;
    
      if not (retCode in [SQL_SUCCESS, SQL_SUCCESS_WITH_INFO]) then
      begin
        errCode := 0;
        errMsgLength := 0;
        SetLength(errMsg, SQL_MAX_MESSAGE_LENGTH);
        SQLInstallerError(1, @errCode, PChar(errMsg), Length(errMsg), @errMsgLength);
        SetLength(errMsg, errMsgLength);
        raise Exception.CreateFmt('Error creating Access database: %s', [errMsg]);
      end;
    end;

文字集合問題

古いAccessデータベースはANSIキャラクタセットでエンコードされていた(新しいものに関してはわからない - おそらくより広い文字集合を使っているだろう)。そのため、非ASCIIキャラクタはDBGidや、他のデータ志向型コントロールで正しく表示されない。これはOnGetTextとOnSetTextをデータセットを開いたのちに適用すれば修正される可能性がある:

pascal
uses
      lconvencoding;
     
    procedure TForm1.SQLQuery1AfterOpen(DataSet: TDataSet);
    var
      i: Integer;  
    begin
      for i:=0 to DataSet.Fields.Count-1 do
      begin
        if DataSet.Fields[i].DataType=ftString then
        begin
          DataSet.Fields[i].OnGetText := @ConvertFromDB;
          DataSet.Fields[i].OnSetText := @ConvertToDB;
        end;
      end;
    end;
     
    procedure TForm1.ConvertFromDB(Sender: TField; var aText: string; DisplayText: Boolean);
    begin
      if not Sender.IsNull then
        aText := WinCPToUTF8(Sender.AsString);  // もしWindowsのデフォルトコードページの場合
    end;
     
    procedure TForm1.ConvertToDB(Sender: TField; const aText: string);
    begin
      if aText <> '' then 
        Sender.Value := UTF8ToWinCP(aText);
    end;

作例データベース

Microsoft AccessにはNorthwindデータベースが付属する

もし、Access Runtimeがインストールされていれば、この別のデータベースをテストデータベースとして利用できる: If you only have the Access Runtime installed, you can use this alternative database from the Mondial project as a test database: [databases.about.com/od/sampleaccessdatabases/a/Microsoft-Access-Sample-Database-Countries-Cities-And-Provinces.htm] [2020年11月時点でこのリンクは切れている]

以下も参照のこと


From the Free Pascal wiki, page "MS Access/ja", as the Internet Archive kept it on 2025-01-17, last changed on 2024-09-25. Copyright stays with the author who wrote it, according to the old wiki's Licensing page. If you have concerns about this material, message the admin.

Revision 1, last changed by WikiArchive .

Talk about this page

Nobody has opened a bench for this page yet. Sign in to open one.