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の参照しているレコードの各フィールドをフォームに設定しています。

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
②SQLを使う
解答例は以下です。

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

今回必要となる「タイトル」「カテゴリ名」「著者」を取得するための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の解答例①で説明しますが、②でも同様です。
まず以下の様にプロシージャを作成します。

Private Sub displayBookInfo(BOOK_ID As Long)

End Sub

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

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

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

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

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

解答例・解説
解答例は以下です。

Private Sub Form_Load()
    If IsNull(OpenArgs) = False Then
        Call displayBookInfo(OpenArgs)
        Me!BOOK_ID = OpenArgs
    End If
End Sub

練習4-2で、BOOK_IDを渡せば書籍情報を表示する処理を作成しました。
今回はOpenArgsでBOOK_IDが取得できるので、引数にOpenArgsを指定しています。
また、編集フォームの「BOOK_ID」コントロールの値もOpenArgsにしています。

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


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

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

・エラーメッセージ

・編集完了メッセージ

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

①レコードセットを使う

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

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

解答例は以下になります。

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

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

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

②SQLを使う
解答例は以下になります。

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

sqlが作成できればExecuteメソッドで実行するだけですが、やはりSQLが複雑になります。
実際にできあがるSQLは以下になります。

UPDATE 蔵書一覧 SET タイトル = 'ハリー・ポッターと秘密の部屋',CATEGORY_ID = 1,著者 = 'J・K・ローリング' WHERE BOOK_ID = 2

プログラムを作成したらローカルウィンドウを使って変数sqlの中身を確認してみてください。


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

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

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

解答例・解説
解答例は以下です。

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

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

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

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

■記事一覧

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

excel_VBAを学んで業務効率化!

excel-vba入門 連載

Recent News

Recent Tips

Tag Search