• 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で記述する場合は、なるべく省略したほうがコードがすっきりします
    「省略できない場合」もあるので、より深い知識が必要になったら調べてみると良いでしょう