初心者です。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が取得できるでしょうか? どこがいけないのか分からなくて。
strSQL1
が実行されて初めて新しいメインIDが作られるので、今の手順では追加前の最終のIDを取るだけですね。コードを記述した通りにプログラムが動いています最新のメインIDが作られてから(
DoCmd.RunSQL strSQL1
を実行してから)メインIDの取得を行いましょうついでに、
strSQL2
の実行前にメインIDが取得できるのでstrSQL2
にメインIDを入れることができます。[用意状況Memo]
やstrSQL3
による追加のアップデート作業も不要ですね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のみ有効と思いますが。別な質問になりすみません。
一対多のテーブルの新規追加するする場合は、じぶんなら下記のようにします。
メインテーブルへの追加(1レコード)はDAOを使って追加。その時にそのレコードのメインID(オートナンバー型)を変数に格納しておく。
サブテーブルへの追加はSQLをDAOでExcuteメソッドで実行して追加。その時に、メインIDは上記の変数のものを利用。
なぜ、DAOを使うかというと、
DoCmd.RunSQLは非同期で実行されるので、SQLの実行が終了する前に次の処理が実行される可能性があるので、それを避けるためです。
また、メインIDをDMaxで取得する場合、マルチユーザーで同時追加する場合に、自分のメインIDでない可能性も捨てきれないので。
メインに追加するのは1レコードだけなのでこのような可能性は低いですが、コード的には大差ないのでより安全性の高いものにしてます。
hatenaさん ありがとうございます。奥の深いものですね。勉強になります。
因みにメインテーブルへDAOで1レコード追加するにはどんなコードになりますでしょうか?
下記のような感じになります。
hatenaさん ありがとうございます。回答頂いたコードで動作確認取れました。
DAOはした事がありませんでしたが勉強して行きます。場合によりますが慣れたらSQLよりも分かり易いかもしれません。
お世話になりました。
DoCmd.RunSQL
とCurrentDb.Execute
は同じことをするという認識で問題ないですデータ処理の流れとしては確認できたような手順で行えばいいですが、hatenaさん指摘のように、それを「保証する」のもデータベースでは必要になりますね
DAOはコード記述になるので、自動整形や構文エラーチェックが使えたりしますが、SQL実行は文字列を渡すだけなのでその文字列が正しいかどうかは実行してみないと分からないという違いがありますね
単純な記述部分でも、SQLはフィールドを並べてから値を並べるので、フィールドと値の対応が分かりにくいのは扱いにくいところだと思っています
hirotonさん ありがとうございます。参考になります。DAOはそういうメリットもあるのですね。
まだまだ手探りでしてますので一つ一つ勉強です。
お世話になりました。