Microsoft Access 掲示板

メインテーブルのIDのMAX値が思うように取得できない

8 コメント
views
4 フォロー

初心者です。T支給Main(メインID:オートナンバー, 支給日付:日付型 ,その他)とT支給Sub(明細ID:オートナンバー, メインID:数値型, 部品ID:数値型, その他)でメインIDでリレーションさせてます(親子テーブル)。
これに別テーブルから新規レコードとして追加させたくて所定のフォームのコマンドボタンに下記コードを記述してます。(変数宣言は省略してます)
'メインテーブルへの追加SQL
       strSQL1 =
            "INSERT INTO [T支給Main] ([支給日付], [支給先選択], [支給方法選択], [部材発送はまだ]) " &

            "VALUES (#" & dt1 & "#," & sikyusaki & ", 1, -1);"
    'サブテーブルへの追加SQL
       strSQL2 =
           "INSERT INTO [T支給Sub] ([部品ID], [支給数], [用意状況Memo]) " &

           "SELECT [材料支給ファイル対象ID], [注残の合計], [memo] " & _
           "FROM [T部材発注accessからIN_直送分];"

   'サブテーブルへの支給IDをメインIDと同じに更新
       メインID = DMax("[支給ID]", "T支給Main") '追加したメインレコードのID取得
       strSQL3 =
           "UPDATE [T支給Sub]" &

           "SET [用意状況Memo] = '今回追加した分' ,[支給ID]=" & メインID & " " & _
           "WHERE [支給ID] Is Null;"
そして DoCmd.RunSQL strSQL1~3で実行としてます。
レコード追加はされるのですがT支給Subの支給IDにはすでに登録済みの最終値となってしますのです。T支給Mainには新規レコードになっていますがT支給Subのデータはない状態です。
メインID = DMax("[支給ID]", "T支給Main")が直近で登録済みの値の取得になっているのが原因の様です。
どうすれば処理途中の支給IDが取得できるでしょうか? どこがいけないのか分からなくて。

beginner
作成: 2024/08/01 (木) 08:54:24
通報 ...
1
hiroton 2024/08/01 (木) 09:28:22 36850@f966d

メインID = DMax("[支給ID]", "T支給Main") '追加したメインレコードのID取得

そして DoCmd.RunSQL strSQL1~3で実行としてます。

strSQL1が実行されて初めて新しいメインIDが作られるので、今の手順では追加前の最終のIDを取るだけですね。コードを記述した通りにプログラムが動いています

最新のメインIDが作られてから(DoCmd.RunSQL strSQL1を実行してから)メインIDの取得を行いましょう

ついでに、strSQL2の実行前にメインIDが取得できるのでstrSQL2にメインIDを入れることができます。[用意状況Memo]strSQL3による追加のアップデート作業も不要ですね

2
beginner 2024/08/01 (木) 10:14:59 ddfe5@a5aee

hirotonさん ありがとうございます。指摘通りに変更したら上手く出来ました。確かにそのままだと メインID = DMax("[支給ID]", "T支給Main") はメインテーブルに追加前に取得されますね。初歩的なミスでした。strSQL3の内容も2の追加に入れることが出来ました。最終定期にstrSQLを1,2分けずに  strSQL =1の処理⇒CurrentDb.Execute strSQL, dbFailOnErrorで実行、DMaxの取得、 strSQL =2の処理⇒CurrentDb.Execute strSQL, dbFailOnErrorで実行にしました。SQL実行するのに DoCmd.RunSQLしか使った事がなかったのですが CurrentDb.Execute strSQL, dbFailOnError (ネットからの情報で知ったコード) は同じ動きをする認識でいいでしょうか? これはアクションSQLのみ有効と思いますが。別な質問になりすみません。

3

一対多のテーブルの新規追加するする場合は、じぶんなら下記のようにします。

メインテーブルへの追加(1レコード)はDAOを使って追加。その時にそのレコードのメインID(オートナンバー型)を変数に格納しておく。

サブテーブルへの追加はSQLをDAOでExcuteメソッドで実行して追加。その時に、メインIDは上記の変数のものを利用。

なぜ、DAOを使うかというと、
DoCmd.RunSQLは非同期で実行されるので、SQLの実行が終了する前に次の処理が実行される可能性があるので、それを避けるためです。

また、メインIDをDMaxで取得する場合、マルチユーザーで同時追加する場合に、自分のメインIDでない可能性も捨てきれないので。

メインに追加するのは1レコードだけなのでこのような可能性は低いですが、コード的には大差ないのでより安全性の高いものにしてます。

4
beginner 2024/08/01 (木) 11:13:43 ddfe5@a5aee

hatenaさん ありがとうございます。奥の深いものですね。勉強になります。
因みにメインテーブルへDAOで1レコード追加するにはどんなコードになりますでしょうか? 

5

下記のような感じになります。

    '前略
    Dim rs As DAO.Recordset, MainId As Long
    Set rs = CurrentDb.OpenRecordset("T支給Main", dbOpenTable, dbAppendOnly)
    rs.AddNew 
    rs!支給日付 = dt1 'dt1 はDate型
    rs!支給先選択 = sikyusaki
    rs!支給方法選択 = 1
    rs!部材発送はまだ = -1
    MainId = rs!メインID '生成されたメインID
    rs.Update
    rs.Close

    Dim strSQL As String
    strSQL = "INSERT INTO [T支給Sub] ([メインID], [部品ID], [支給数], [用意状況Memo]) " &
    "SELECT " & MainId &  " As [メインID], [材料支給ファイル対象ID], [注残の合計], [memo] " & _
    "FROM [T部材発注accessからIN_直送分];"
    CurrentDb.Execute strSQL, dbFailOnError
6
beginner 2024/08/01 (木) 11:59:18 ddfe5@a5aee

hatenaさん ありがとうございます。回答頂いたコードで動作確認取れました。
DAOはした事がありませんでしたが勉強して行きます。場合によりますが慣れたらSQLよりも分かり易いかもしれません。
お世話になりました。

7
hiroton 2024/08/01 (木) 12:26:02 36850@f966d

DoCmd.RunSQLCurrentDb.Executeは同じことをするという認識で問題ないです

データ処理の流れとしては確認できたような手順で行えばいいですが、hatenaさん指摘のように、それを「保証する」のもデータベースでは必要になりますね

DAOはコード記述になるので、自動整形や構文エラーチェックが使えたりしますが、SQL実行は文字列を渡すだけなのでその文字列が正しいかどうかは実行してみないと分からないという違いがありますね
単純な記述部分でも、SQLはフィールドを並べてから値を並べるので、フィールドと値の対応が分かりにくいのは扱いにくいところだと思っています

8
beginner 2024/08/01 (木) 14:50:07 ddfe5@a5aee

hirotonさん ありがとうございます。参考になります。DAOはそういうメリットもあるのですね。
まだまだ手探りでしてますので一つ一つ勉強です。
お世話になりました。