Tips

【Access VBA】実践演習 #4 (編集機能の実装)
2019.08.15

【Access VBA】実践演習 #4 (編集機能の実装)

このシリーズでは書籍管理システムの作成を通して、Access VBAの使い方を学ぶことを目標とします。
データベース操作はDAOを使って実装します。
Accessの基本的な操作は知っているけれど、VBAはあまり書いたことがない方を対象としています。

途中SQLも使いますので、不安な方はこちらの記事等で確認してください。
AccessでSQLの練習

必要なファイルのダウンロードやテーブル等の確認は初回の記事をご覧ください。
【Access VBA】実践演習 #1


今回は「F_書籍編集」の各機能を実装していきたいと思います。

■練習4-1 (BOOK IDコンボボックス)

BOOK IDコンボボックスの値が変わったときに、IDに応じた「タイトル」「カテゴリ」「著者」の
値が各フォームに入力されるようにしてください。

(ヒント)
・コンボボックスの「更新後」イベントを使用(他のイベントでも可)
・FindFirstでレコード検索(Q_書籍検索を使用する場合)

解答例・解説
今回も2パターン紹介します。

①「Q_書籍検索」を使う

今回必要なデータは「Q_書籍検索」に含まれています。
まずはいつも通りOpenRecordsetしますが、この後にFindFirstメソッドを使うのがポイントです。

FindFirstメソッドは引数にWHERE句の条件式を指定します。
今回はBOOK_IDで検索をかけています。

あとは検索した結果rsの参照しているレコードの各フィールドをフォームに設定しています。

[vb] Private Sub BOOK_ID_AfterUpdate()

Dim db As DAO.Database
Dim rs As DAO.Recordset

Set db = CurrentDb
Set rs = db.OpenRecordset("Q_書籍検索", dbOpenDynaset)

rs.FindFirst "BOOK_ID = " & Me!BOOK_ID

Me!タイトル = rs.Fields("タイトル")
Me!カテゴリ = rs.Fields("カテゴリ名")
Me!著者 = rs.Fields("著者")

rs.Close
db.Close

End Sub
[/vb]

②SQLを使う
解答例は以下です。
[vb] Private Sub BOOK_ID_AfterUpdate()

Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim sql As String

sql = "SELECT タイトル,カテゴリ名,著者 FROM 蔵書一覧 LEFT OUTER JOIN カテゴリ一覧 ON 蔵書一覧.CATEGORY_ID = カテゴリ一覧.CATEGORY_ID WHERE BOOK_ID = " & Me!BOOK_ID

Set db = CurrentDb
Set rs = db.OpenRecordset(sql, dbOpenDynaset)

Me!タイトル = rs.Fields("タイトル")
Me!カテゴリ = rs.Fields("カテゴリ名")
Me!著者 = rs.Fields("著者")

rs.Close
db.Close

End Sub
[/vb]

今回必要となる「タイトル」「カテゴリ名」「著者」を取得するためのSQLを用意しています。
「タイトル」「著者」は「蔵書一覧」テーブルから取得できますが、「カテゴリ名」は「カテゴリ一覧」テーブル
から取得するため、外部結合を使用しています。

SQLが完成したらOpenRecordsetの引数に渡して、取得したレコードセットの各フィールドをフォームにセットしています。


■練習4-2 (処理の共通化)

練習4-1で作成した「BOOK_ID_AfterUpdate」の処理を以下に置き換えてください。
また、同じ処理が実行されるように、Subプロシージャ「displayBookInfo」を作成してください。

Private Sub BOOK_ID_AfterUpdate()
    
    Call displayBookInfo(Me!BOOK_ID)
    
End Sub
解答例・解説

練習4-1の解答例①で説明しますが、②でも同様です。
まず以下の様にプロシージャを作成します。
[vb] Private Sub displayBookInfo(BOOK_ID As Long)

End Sub
[/vb] 引数「BOOK_ID」でLong型の値をを受け取れるようにしています。
あとはこの中に練習4-1のプログラムを貼り付けるだけですが、
「Me!BOOK_ID」の箇所を「BOOK_ID」に置き換えてください。(9行目)
[vb] Private Sub displayBookInfo(BOOK_ID As Long)

Dim db As DAO.Database
Dim rs As DAO.Recordset

Set db = CurrentDb
Set rs = db.OpenRecordset("Q_書籍検索", dbOpenDynaset)

rs.FindFirst "BOOK_ID = " & BOOK_ID

Me!タイトル = rs.Fields("タイトル")
Me!カテゴリ = rs.Fields("カテゴリ名")
Me!著者 = rs.Fields("著者")

rs.Close
db.Close

End Sub
[/vb]


■練習4-3 (F_書籍検索から開いた時の処理)

検索機能を作成(第2回)の時に編集ボタンの処理を作成しました。
「F_書籍検索」から編集ボタンをクリックしたときに、該当の書籍の情報を表示させてください。

(ヒント)
・フォームの「読み込み時」イベント(Form_Load)を使用。(Form_Open等でもOK)
・OpenArgsがNullでない場合は練習4-2で作成した「displayBookInfo」に渡す。

解答例・解説
解答例は以下です。
[vb] Private Sub Form_Load()
If IsNull(OpenArgs) = False Then
Call displayBookInfo(OpenArgs)
Me!BOOK_ID = OpenArgs
End If
End Sub
[/vb] 練習4-2で、BOOK_IDを渡せば書籍情報を表示する処理を作成しました。
今回はOpenArgsでBOOK_IDが取得できるので、引数にOpenArgsを指定しています。
また、編集フォームの「BOOK_ID」コントロールの値もOpenArgsにしています。

IsNullの判定は、OpenArgsが空の時(F_トップページから飛んだ時など)にエラーを吐かないための処理です。


■練習4-4 (編集ボタン)

今回のメインとなる編集ボタンの処理です。
編集ボタンをクリックすると、対象の書籍の情報を更新します。
登録の時と同じように、各フォームが空の場合はエラーメッセージを表示し、
編集完了時にもダイアログを表示するようにしてください。

・エラーメッセージ

・編集完了メッセージ

解答例・解説
今回も2パターン紹介します。

①レコードセットを使う

未入力チェックに関する説明は登録時と同様なので割愛します。

レコードの編集は以下の流れで処理をしています。
1.「蔵書一覧」テーブルのレコードセットを取得
2. 対象のレコードへ移動(FindFirstメソッド)
3. レコードを編集状態にする(Editメソッド)
4. データを編集して、レコードセットを更新

解答例は以下になります。
[vb] Private Sub 編集ボタン_Click()

‘ 入力チェック
If IsNull(Me!BOOK_ID) Then
MsgBox "BOOK IDが空です。", vbExclamation
Exit Sub
End If

If IsNull(Me!タイトル) Then
MsgBox "タイトルが空です。", vbExclamation
Exit Sub
End If

If IsNull(Me!カテゴリ) Then
MsgBox "カテゴリが空です。", vbExclamation
Exit Sub
End If

If IsNull(Me!著者) Then
MsgBox "著者が空です。", vbExclamation
Exit Sub
End If

‘ 編集処理
Dim db As DAO.Database
Dim rs As DAO.Recordset

Set db = CurrentDb
Set rs = db.OpenRecordset("蔵書一覧", dbOpenDynaset)

‘ レコード検索
rs.FindFirst "BOOK_ID = " & Me!BOOK_ID

‘ 編集
rs.Edit
rs.Fields("タイトル") = Me!タイトル
rs.Fields("CATEGORY_ID") = Me!カテゴリ.Column(0)
rs.Fields("著者") = Me!著者
rs.Update

‘ Close
rs.Close
db.Close

MsgBox "書籍情報を更新しました。", vbInformation

End Sub
[/vb]

レコードセットを扱う上で注意することとして、
今どの行(レコード)を参照しているかを気にする必要があります。
27行目でOpenRecordsetした直後は取得した中で一番上のレコードを参照しています。
今回のように更新したい行が決まっている場合は、処理を開始する前に
FindFirst等のメソッドで対象のレコードへ移動する必要があります。(29行目)

また、編集の処理に関しては基本的には登録の時と似ていますが、
既存のレコードを更新する場合には最初に「rs.Edit」を使ってレコードを編集状態にします。
(登録の時のAddNewの代わりと考えても良いかと思います。)

②SQLを使う
解答例は以下になります。
[vb] Private Sub 編集ボタン_Click()

If IsNull(Me!BOOK_ID) Then
MsgBox "BOOK IDが空です。", vbExclamation
Exit Sub
End If

If IsNull(Me!タイトル) Then
MsgBox "タイトルが空です。", vbExclamation
Exit Sub
End If

If IsNull(Me!カテゴリ) Then
MsgBox "カテゴリが空です。", vbExclamation
Exit Sub
End If

If IsNull(Me!著者) Then
MsgBox "著者が空です。", vbExclamation
Exit Sub
End If

Dim db As DAO.Database
Dim sql As String

sql = "UPDATE 蔵書一覧 SET タイトル = ‘" & Me!タイトル & "’,CATEGORY_ID = " & Me!カテゴリ.Column(0) & ",著者 = ‘" & Me!著者 & "’ WHERE BOOK_ID = " & Me!BOOK_ID

Set db = CurrentDb
db.Execute sql

db.Close

MsgBox "書籍情報を更新しました。", vbInformation

End Sub
[/vb]

sqlが作成できればExecuteメソッドで実行するだけですが、やはりSQLが複雑になります。
実際にできあがるSQLは以下になります。
[sql] UPDATE 蔵書一覧 SET タイトル = ‘ハリー・ポッターと秘密の部屋’,CATEGORY_ID = 1,著者 = ‘J・K・ローリング’ WHERE BOOK_ID = 2
[/sql] プログラムを作成したらローカルウィンドウを使って変数sqlの中身を確認してみてください。


■練習4-5 (リセットボタン)

最後にリセットボタンの処理を実装しましょう。
ボタンクリック時にBOOK_IDの現在の値(編集前の値)を反映するようにします。
その際以下のような確認メッセージを表示して、OKのときだけリセットしましょう。

(ヒント)
・練習4-2で作成したdisplayBookInfoを利用する。
・BOOK_IDが空の時は処理をしない。

解答例・解説
解答例は以下です。
[vb] Private Sub リセットボタン_Click()

‘ BOOK_IDが空なら中断
If IsNull(Me!BOOK_ID) Then
Exit Sub
End If

‘ 確認メッセージ
Dim m As Long
m = MsgBox("編集中の内容がリセットされます。", vbExclamation + vbOKCancel)

‘ OK以外なら中断
If m <> vbOK Then
Exit Sub
End If

‘ リセット処理
Call displayBookInfo(Me!BOOK_ID)

End Sub
[/vb]

練習4-2で作成したdisplayBookInfoがここでも利用できるため、
比較的シンプルなコードになるかと思います。

今回は編集機能の作成を行いました。
共通処理をまとめるところはVBAの復習になったかと思いますし、
親フォーム(F_書籍検索)から子フォーム(F_書籍編集)への値の受け渡しは応用が効く処理だったと思います。

次回は貸出と返却機能を作成し、一通り完成となる予定です!

■記事一覧

#1 (準備とトップページの処理)
#2 (検索機能の実装)
#3 (登録機能の実装)
#4 (編集機能の実装)
#5 (貸出・返却機能の実装)

excel_VBAを学んで業務効率化!

excel-vba入門 連載

Recent News

Recent Tips

Tag Search