Microsoft Access 掲示板

1つのコンボボックスから、複数のテキストボックスに同時入力したい

9 コメント
views
4 フォロー

先日、コンボボックスで選んだデータを、もう一つのテキストボックスにも同時入力したい、という要望についてアドバイスを求めたものです。そのときは、コンボとテキストボックスをつなげばいい、と教えてもらいました。

今度は、1つのコンボボックスから、複数のテキストボックスに同時入力したい、という要望についてお尋ねします。競馬の話なんですが、日にちごとにレースのデータを並べて表示した帳票フォームがあります。その中に「天候」というコンボと、レース情報の天候に紐づいた天候というテキストボックスがあります。1日の間に天候は変わっていくので、レースごとに天候を設定したいのですが、一つ一つ設定するのはめんどくさいので、一つ「晴れ」と設定したら、テーブルの全部のレースの天候のところに「晴れ」を入力して保存したいと思ってます。これは更新クエリの出番だと思うのですが、

'Private Sub コンボ353_AfterUpdate()

'UPDATE public_stb_ra_time_shokin_5 INNER JOIN public_stb_ra_tpc_sabun ON public_stb_ra_time_shokin_5.race_id = public_stb_ra_tpc_sabun.race_id SET public_stb_ra_tpc_sabun.suitei_tenko = [Me]![form]![コンボ_353].[value]
'WHERE (((public_stb_ra_time_shokin_5.hizuke)=[Me]![開催日].[value]));

'Me.Refresh
'End Sub

と書いてもうまくできません。それともDAOで回すべきでしょうか? すいませんが教えて下さい。

ちばまもる
作成: 2024/04/03 (水) 13:57:41
通報 ...
1
hiroton 2024/04/03 (水) 14:40:14 f575b@f966d

VBAでクエリを動的に生成し実行する場合、「クエリを実行する」という命令を記述する必要があります。

DoCmd.RunSQL メソッド (Access)

Database.Execute メソッド (DAO)

Private Sub コンボ353_AfterUpdate()

    Dim SQL As String

    SQL = _
        " UPDATE public_stb_ra_time_shokin_5 INNER JOIN public_stb_ra_tpc_sabun ON public_stb_ra_time_shokin_5.race_id = public_stb_ra_tpc_sabun.race_id SET public_stb_ra_tpc_sabun.suitei_tenko = " & [Me]![form]![コンボ_353].[value] & _
        " WHERE (((public_stb_ra_time_shokin_5.hizuke)=" & [Me]![開催日].[value] & "));"

    CurrentDb.Execute SQL 
    Me.Refresh
End Sub

※クエリ(SQL構文)そのものの正否は見ていません


「フォームに表示されている全データを更新したい」のであれば、フォームのレコードセットを更新していく方法もありだと思います

Private Sub コンボ353_AfterUpdate()
    With Me.Recordset.Clone
        Do Until .EOF
            Me!suitei_tenko = Me!コンボ_353
            .MoveNext
        Loop
        .Close
    End With
    Me.Refresh
End Sub
2
ちばまもる 2024/04/03 (水) 18:08:19 0bf9d@6f372

早速返信していただきありがとうございます。恥ずかしいですけど、アップした画像のようなフォームになっています。親フォームがF_T0指数評価用で、サブフォームが埋め込み47またはF_TP指数です。(サブフォームを指定するときはどっちを書いたらいいものかいつも迷いますが、記憶では埋め込み47を書くのが正しいのではないか、と)。親フォームにあるテキストボックスの[開催日]を見て、テーブルの該当箇所にコンボボックスの選択値=天気を入力しようと思ってます。が、できません。Formが見つかりません、というメッセージが出てきます。よろしくお願いします。

Private Sub コンボ351_AfterUpdate()
    Dim SQL As String
    SQL = "UPDATE public_stb_ra_time_shokin_5 INNER JOIN public_stb_ra_tpc_sabun ON public_stb_ra_time_shokin_5.race_id = public_stb_ra_tpc_sabun.race_id SET public_stb_ra_tpc_sabun.suitei_tenko = " & [Forms]![F_T0指数表示用]![埋め込み47]![Form]![コンボ351].[Value] & "WHERE (((public_stb_ra_time_shokin_5.hizuke) = " & [Forms]![F_T0指数表示用]![開催日].[Value] & "));"
    CurrentDb.Execute SQL
    Me.Refresh
End Sub

3
ちばまもる 2024/04/03 (水) 18:10:58 0bf9d@6f372

画像1

4
ちばまもる 2024/04/03 (水) 18:13:38 0bf9d@6f372

追伸 それとフォームのレコードセットを更新する方法のほうがよいのかもしれないですが、そっちの理屈はまったくわけがわからないです。

6

フォームのレコードセットはDAOレコードセットなので、下記あたりを参考に学習してください。

VBA DAO レコードセット 更新 - Google 検索

フォームのレコードセットについては、下記で詳しく解説しています。

フォームの Recordset, RecorsetClone, RecordSet.Clone の違いとは? - hatena chips

5
hatena 2024/04/03 (水) 18:27:11 修正

コンボ351 というのはサブフォームにあるのですよね。
ならば、hirotonさんが提案されたフォームのレコードセットを更新していく方法がいいと思いますよ。

Private Sub コンボ351_AfterUpdate()
    With Me.Recordset.Clone
        Do Until .EOF
            .Edit
            !suitei_tenko = Me!コンボ351
            .Update
            .MoveNext
        Loop
        .Close
    End With
    Me.Recalc
End Sub

更新クエリで、サブフォームに記述するコードなら、Me(サブフォーム自身) と Parent(親フォーム) を使えば、
ややこしい参照式を使う必要はないです。

SQL = "UPDATE public_stb_ra_time_shokin_5 INNER JOIN public_stb_ra_tpc_sabun " & _
      "ON public_stb_ra_time_shokin_5.race_id = public_stb_ra_tpc_sabun.race_id " & _
      "SET public_stb_ra_tpc_sabun.suitei_tenko = " & Me.コンボ351.Value & _
      "WHERE public_stb_ra_time_shokin_5.hizuke = " & Parent!開催日.Valu & "));"
7
ちばまもる 2024/04/03 (水) 21:33:32 0bf9d@6f372

ありがとうございます。フォームのレコードセットを更新していく方法で、見事できました。期待以上です。しかし、Hatenaさんの手にかかれば何でも魔法のように解決しちゃいますね。いつもありがとうございます。書いていただいたレコードセットについての記事も読んで勉強します。

8
hiroton 2024/04/04 (木) 18:49:44 c3230@f966d

あぁ、コードがめちゃくちゃでしたね。ごめんなさい
hatenaさんが正しいコード例を提示してくださっているのでそちらを参考にしてください

クエリを使うか、レコードセットを操作するかについては、フォームに読み込んだレコードを操作するのであれば、圧倒的にDAOによるレコードセットの操作のほうが楽だと思います

開いたフォームがすでにレコードセットを開いているので、よくあるレコードセットを扱うための魔法の言葉が不要で、Withステートメントの活用により余計な変数も不要になるので


フォームのレコードセットを操作する方法はいくつかあります。(hirotonの回答がめちゃくちゃなのも、これらを適当に組み合わせてしまっているからです)

DoCmdによるフォームの操作

If Me.CurrentRecord < 1 Then Exit Sub
DoCmd.GoToRecord , , acLast
Do Until Me.CurrentRecord = 1
    Me!suitei_tenko = Me!コンボ351
    DoCmd.GoToRecord , , acPrevious
Loop
Me!suitei_tenko = Me!コンボ351

ACCESSの機能を使ってフォームを見たまま操作する例です。見たまま、レコードを移動させながら操作するので、suitei_tenkoもMeからの参照で現在のカレントレコードのフィールドの値を修正します
レコードセットの操作と異なり、レコードが無い場合の操作を行うとエラーが発生するので、それようの対策が必要です
「マクロ」で作る場合の理論をそのままVBAでコードにするとこんな感じでしょう

Me.Recordsetを操作

With Me.Recordset
    .MoveFirst
    Do Until .EOF
        .Edit
        !suitei_tenko = Me!コンボ351
        .Update
        .MoveNext
    Loop
End With
With Me.Recordset
    .MoveFirst
    Do Until .EOF
        Me!suitei_tenko = Me!コンボ351
        .MoveNext
    Loop
End With

表示しているフォームそのもののレコードを扱います。レコードセットのレコードを移動させると、フォーム上のレコードも移動するので、レコードの移動だけレコードセットを操作して、レコードの編集はフォーム上のコントロールを操作するとかいう訳の分からないコードを組むこともできます。(コードが短くなるだけで大したメリットはない)

Me.RecordsetCloneを操作

With Me.RecordsetClone
    .MoveFirst
    Do Until .EOF
        .Edit
        !suitei_tenko = Me!コンボ351
        .Update
        .MoveNext
    Loop
End With

フォームに読み込まれているレコードセットを直接操作します。ただし、表示中のレコードは移動しません。Meによる参照と、レコードセットからの参照で、参照しているレコードを別々に持つことになります

Me.Recordset.Cloneを操作
(コードは省略)
全く同じレコードセットを新しく生成します
新規でレコードセットが生成されるので、常にレコードセットの先頭にカーソルがある状態のレコードセットになります。(DoCmd.GoToRecordMoveFirstのような、全件を操作するための準備がいらない)
新規でレコードセットを生成しているので、閉じる処理(Close)が必要
フォームとは関係ないレコードセットを操作するので、フォームに反映させる処理(recalc/refresh/requery)が必要

9
hiroton 2024/04/04 (木) 19:26:39 c3230@f966d

何かを参照する場合は、「コードの実行場所」と「コードの実行場所から見た操作したい相手の場所」を常に意識することが大事です。

すべて無視して、ACCESS本体から見た「Forms!~」という記述も可能ですが、hatenaさん指摘のように、「コードの実行場所自身=>Me」や、「サブフォームからみた親フォーム=>Me.Parent」、「親フォームから見たサブフォーム=>Me![サブフォーム名].Form」等の参照方法を覚えるとコードが簡素に記述できます

また、参照に用いる場合の[]使い方も覚えましょう。これは、基本的に「名前」を指定するときに用いる記号です。ACCESS本体が持つ機能(キーワード)に使うことはできません

たとえば、「天候」を保存するために用意したフィールド「suitei_tenko」を指定する場合に、[suitei_tenko]等記述します。「フォームに読み込んだそれを参照する」なら

Debug.Print Me![suitei_tenko]

のようになります

通常「Me」とは、コードを実行したオブジェクトを参照するキーワードで何かの名前ではありません。[Me]と記述した場合、「Me」と名前を付けた何か(フィールドとか、テキストボックスとか)を参照する記述となります。そのような「何か」が無ければ参照先が見つからないというエラーが発生します

また、[]は省略可能な記述で、ACCESS上(フォームやレポート等)で記述すると自動で付加されますが、VBAで記述する場合は、なるべく省略したほうがコードがすっきりします
「省略できない場合」もあるので、より深い知識が必要になったら調べてみると良いでしょう