Microsoft Access2003

Page 8 (2005/01)

DAOとRecordSetオブジェクト
フォームでデータを扱うのには限度があるので、プログラムでデータを扱う場合、フォームの外で直接データを処理する必要に迫られます。
そこでDAO(データ・アクセス・オブジェクト)ということになります。
ある意味、データベース・ソフトの要になる部分だけに面白みもあります。
RecordSetオブジェクトの種類は4種類

(1)テーブル・タイプ(dbOpenTable)          ローカルなテーブルそのものをオープンする。リンクテーブルはだめ。クエリーなどもだめ。
                                メリットはインデックスを使える(Seekメソッドが使える)

(2)ダイナセット・タイプ(dbOpenDynaset)       ローカルなテーブルとリンクテーブルが使える。クエリーも使える。複数のテーブルを同時に更新可能。
                               テーブルとダイナセットは相互に更新する。

(3)スナップショット・タイプ(dbOpenSnapShot)    更新できない。
(4)前方スクロール・タイプ(dbOpenForwardOnly)  レコードを前方にしかスクロールできないスナップショット

データ参照用の(3)と(4)よりも、使用頻度は(1)と(2)が圧倒的に多いようです。構文は以下の通りです。
Set recordset = object.OpenRecordset (source, type, options, lockedits)

OpenRecordsetはメソッドです。
source はファイル名またはクエリー名を文字列で渡します。
type  には上記のdbOpenTableなどのレコードセットのタイプを指定します。
     
typeを指定しない場合、sourceがカレントデータベースのテーブルの場合はテーブル・タイプ、リンクテーブルやクエリーの場合はダイナセット・タイプとして開かれます。基本的なパターンは以下の通りです。

Dim db As Database             データベース型オブジェクト変数を宣言
Dim rs As Recordset             レコードセット型オブジェクト変数を宣言
Set db = CurrentDb              オブジェクト変数dbにカレント・データベースをセット
Set rs = db.OpenRecordset("俳優名")   オブジェクト変数rsにカレントデータベースのテーブル「俳優名」をセット
rs.AddNew                    AddNewメソッドでレコードセットに新しいレコードを追加
rs![俳優名] = NewData            レコードセットの俳優名フィールドに変数の値を代入
rs.Update                     レコードセットを更新する
フォームを基にしたRecordsetオブジェクト

フォームのプロパティ RecordsetClone を使います。これで作られるレコードセットはダイナセット・タイプですので、フォームのレコードソースがテーブルでもクエリーでもOKです。

Private Sub cboタイトル検索_AfterUpdate()
   ' コントロールの値と一致するレコードを検索する
   Dim rs As Object           'As Recordsetが好ましい
   Set rs = Me.RecordsetClone    'Forms!frmDVD.RecordsetClone と同じ
   rs.FindFirst "[DVD_ID] = " & Me![cboタイトル検索]   'ダイナセット・タイプではSeekメソッドは使えないのでFindメソッドを使う
   If Not rs.EOF Then Me.Bookmark = rs.Bookmark    'ブックマークでフォームとレコードセットのレコードを同期させる
End Sub
テーブルタイプRecordsetのインデックスとSeek検索

Sub RecordsetSeek()
  Dim dbs As Database, rs As Recordset
  Set dbs = CurrentDb
  Set rs = dbs.OpenRecordset("俳優名")
  rs.MoveFirst                                  'インデックス無し、通常の状態のテーブルの先頭レコードに移動
  MsgBox "インデックス無しの最初のレコードは " & rs!俳優名
  rs.Index = "俳優名"                              '俳優名フィールドにはIndexが作ってあるのでここでセットする
  rs.MoveFirst                                   'インデックスの先頭のレコードに移動
  MsgBox "インデックスをセットした最初のレコードは " & rs!俳優名
  rs.Seek "=", "ジュリエット・ビノシュ"                    'Seekの引数は検索の条件と検索値
  If rs.EOF Then
    MsgBox "登録されていません"
  Else
    MsgBox MsgBox rs!俳優名 & " の俳優名IDは " & rs!俳優名ID
  End If
  rs.Close
  Set dbs = Nothing
End Sub
クエリ(SQL)を使ったダイナセット・タイプのRecordset

Sub RecordsetQuery()
  Dim dbs As Database, rs As Recordset
  Dim strQuery As String
  strQuery = "SELECT DVD.DVD_ID, DVD.タイトル, DVD.監督名, 監督名.監督名 " _
        & "FROM 監督名 INNER JOIN DVD ON 監督名.監督名ID = DVD.監督名 " _
        & "WHERE (((監督名.監督名)='アンソニー・ミンゲラ'));"
  Set dbs = CurrentDb
  Set rs = dbs.OpenRecordset(strQuery)
  Do Until rs.EOF
    Debug.Print rs!タイトル
    rs.MoveNext
  Loop
  Debug.Print rs.Type = dbOpenDynaset
End Su
SQLを文字型変数に入れるのではなくQueryDefを作ってRecordSetを開く
こちらの方が処理速度は速い。この例では一度TestSQLが作られると、2度目に実行するとCreateQueryDefでエラーになります。

Sub RecordsetSQL()
  'QueryDefを作ってからレコードセットを開く
  Dim dbs As Database, rs As Recordset
  Dim qdf As QueryDef
  Set dbs = CurrentDb
  Set qdf = dbs.CreateQueryDef("TestSQL")
  qdf.SQL = "SELECT DVD.DVD_ID, DVD.タイトル, DVD.監督名, 監督名.監督名 " _
        & "FROM 監督名 INNER JOIN DVD ON 監督名.監督名ID = DVD.監督名 " _
        & "WHERE (((監督名.監督名)='アンソニー・ミンゲラ'));"
  Set rs = dbs.OpenRecordset("TestSQL")
  Do Until rs.EOF
    Debug.Print rs!タイトル
    rs.MoveNext
  Loop
  Debug.Print rs.Type = dbOpenDynaset
  rs.Close
  Set dbs = Nothing
End Sub
RecordsetのRecordCountプロパティ
Recordsetのレコードの総数を返すプロパティですが、テーブルタイプとダイナセット・タイプでは違いがあります。

Set rs = dbs.OpenRecordset("DVD")
MsgBox "RecordCountの値は " & rs.RecordCount

このように、テーブルタイプですと、単純に総数を返しますが、ダイナセット・タイプとスナップショット・タイプですと、ここで返る値は 1 です。
RecordCountプロパティの値は"実際にアクセスしたレコードの数"ということですから、最後のレコードまで移動させなくてはなりませんので、MoveLastで最後のレコードまで移動させます。

Set rs = dbs.OpenRecordset("DVD",dbOpenDynaset)
rs.MoveLast
MsgBox "RecordCountの値は " & rs.RecordCount

Bookmarkプロパティ

「Recordset オブジェクトのプロパティの 1 つです。カレント レコードを識別するバイナリ文字列が格納されます。Bookmark プロパティの値を文字列変数に代入してから別のレコードに移動した場合、その文字列変数の値を Bookmark プロパティに再設定して、元のレコードを再びカレント レコードにすることができます。」

Sub BookmarkTest()
  Dim dbs As Database, rst As Recordset
  Dim vBookmark As String    'VariantでもStringでもOK
  Set dbs = CurrentDb
  Set rst = dbs.OpenRecordset("俳優名", dbOpenSnapshot)
  rst.FindFirst "[俳優名] = 'ジュード・ロウ'"
  If rst.NoMatch Then
    MsgBox "見つかりません"
  Else
    vBookmark = rst.bookmark
    MsgBox rst!俳優名 & "にBookmarkしました"
    rst.MoveLast
    MsgBox "最後のレコード " & rst!俳優名 & " に移動しました"
    rst.bookmark = vBookmark                         ← ここで変数をレコードセットのBookmarkに入れてレコードを戻す
    MsgBox "Bookmarkで戻りました " & rst!俳優名
  End If
End Sub

「フォームを基にしたRecordsetオブジェクト」のサンプルコードではフォームでBookmark使うケースを紹介しています。

パラメータ クエリーをRecordsetで使う
テーブルDVDには「制作年」という文字型フィールドがあるのですが、これを使って指定した範囲のレコードを抽出するパラメータ・クエリをレコードセットで開いてリストボックスに表示させます。
フォームからSubプロシージャを呼び出しています。
下のコードは短いものですけど、ちょっと分かりにくいかも・・。
Sub ParameterQueryTest(strStart As String, strEnd As String)
  Dim dbs As Database, rst As Recordset, qdf As QueryDef
  Dim strSQL As String, strList As String
  Set dbs = CurrentDb
  
  strSQL = "PARAMETERS [開始年] string,[終了年] string ;"
  strSQL = strSQL & " SELECT * FROM DVD WHERE (((制作年) Between [開始年] And [終了年]))"
  strSQL = strSQL & " ORDER BY 制作年;"
  
  Set qdf = dbs.CreateQueryDef("", strSQL)    '新しいクエリを名前を付けずに作成
  qdf.Parameters("開始年") = strStart       'フォームの値をパラメーターに代入する
  qdf.Parameters("終了年") = strEnd
  Set rst = qdf.OpenRecordset(dbOpenSnapshot, dbForwardOnly)     'クエリからレコードセットをオープン
  
  While rst.EOF = False                          'クエリのレコードセットのレコードを値リストのための変数に代入する
    strList = strList & rst!制作年 & " " & rst!タイトル & ";"
    rst.MoveNext
  Wend
  リストボックス5.RowSourceType = "value list"      '値集合タイプを値リストに設定
  リストボックス5.RowSource = strList            'リストボックスの値集合ソースに変数をセットする
  Me.Repaint                            'これを入れないと画面にリストの値が表示されない
End Sub
文字列変数strSQLに長いSQLステートメントを入れてます。まだこれでも短いほうか?
通常、選択クエリはSelectから始まるのですけど、パラメータ・クエリはその前にParameters文が付きます。パラメータの名前とそのデータタイプを列記するわけで、この場合は二つです。

このパラメータ・クエリはユーザー・インターフェースで実行すると、以下のようにパラメータ入力を要求してきます。
下の図は連続した処理を一枚の絵にまとめたものですが、入力された「年」の範囲に該当するレコードを抽出してくれます。該当するレコード3個が表示されてます。


このままフォームのなかで使うと、細かなエラーチェック処理ができないので、フォームのコントロールからパラメータを受け取るようにしたのが上のプロシージャです。
Set qdf = dbs.CreateQueryDef("", strSQL)
 カレントデータベースのなかに、名前を付けずにSQL文からクエリを作りオブジェクト変数に入れます。
qdf.Parameters("開始年") = strStart
qdf.Parameters("終了年") = strEnd
 QueryDefのParameteersコレクションのなかの二つのパラメータに、引数として受け取った変数の値を代入しています。
Set rst = qdf.OpenRecordset(dbOpenSnapshot, dbForwardOnly)  
 そしてそのクエリからレコードセットをスナップショットで開きます。


Page Topへ戻る