こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

AccessVBA サブフォームとデータベースの連携について

現在、変な現象が起きており、困っています。
使用している環境はAccess2003です。
同現象に立ち会ったことのある方がいらっしゃいましたら回答をお願いします。

フォーム内部にサブフォーム表示領域を用意し、サブフォームでは以下のようにSQL文をセットし、MDBファイル(自分)のテーブルの内容を表示しています。
Me.RecordSource = "SELECT * FROM [マスタ] WHERE [削除] = No ORDER BY [コード]"
表示できています。書き換えることも出来ます。
ですが、フィールド編集「直後」に更新処理(VBAでの外部データベースへの保存処理)をかけると、なぜか失敗することがあります。
直後ではなく、他レコードのフィールドを選択してから更新処理を実行すると、うまくいきます。
失敗といっても完全に失敗するわけではなく、以下の動作になります。
たとえば、[コード]8を9に書き換える処理。
ソースは書ききれないため、処理内容だけ記述します。

[[ 失敗時 ]]
UPDATE [テーブル名] SET [コード] = 9(エラーにならない)
上記のテーブルのレコードを全てそのまま外部MDBに書き込む処理が走るが、その時の[コード]が書き換えられておらず、8のまま外部データベースに書き込まれる。
[[ 成功時 ]]
UPDATE [テーブル名] SET [コード] = 9(エラーにならない)
[コード]には9書き込まれ、外部MDBに正しく書き込まれる。

まったく同じ処理が実行されます。同じデータ内容や状況で、操作方法を変えるだけで現象を引き起こせます。
成功時と失敗時の違いは、上記の通りフィールドを更新した直後に違うレコードを選択するかしないかという事、これしか現在発見できていません。
上記の現象を回避する方法、ご存知の方がいらっしゃいましたら、教えてください。
宜しくお願いします。

投稿日時 - 2008-12-11 17:08:29

QNo.4547456

困ってます

質問者が選んだベストアンサー

No.2, 4です。

> レコードであればどこでもいいのでしょうか?

とりあえず、SetFocusが可能なコントロールであれば、どこでも構いません。
(フォーカス取得時などにマクロ・VBAを組み込んでいるようなコントロールは、
そのマクロ・VBAを意図的に起動させたいということでもない限り、避けた方が
無難ですが)

なお、もしもそのサブフォームにヘッダやフッタがあり、そこにフォーカスを
移せるコントロールがある場合は、そのコントロールに移動した時点で
レコードが保存されます(=acCmdSaveRecordが不要化する)ので、
併せて参考まで。

投稿日時 - 2008-12-12 22:45:35

補足

回答ありがとうございます。
確かに理論上、いけそうな気がします!
ヘッダとフッタはあったのですがレコードと連結させていません。念のためフォーカスを移動してみましたが、やっぱりダメでした。
レコードが複数ある場合に次のレコードに移動させ、フォーカスを移動させてみましたが、同様にうまく更新されませんでした。
各場所でacCmdSaveRecordをやってみたのですが、なぜかうまく働きません。

投稿日時 - 2008-12-17 10:49:56

このQ&Aは役に立ちましたか?

1人が「このQ&Aが役に立った」と投票しています

回答(6)

操作状況が見えませんが・・・。

<外部データベースへの保存処理ボタンを配置している場合>

保存処理が完了されるまでは無効化。
こうだと、ユーザが打キーして保存しないままに保存処理ボタンをクリックは不可に。

目的のフィールドが更新された時に

SendKeys "+({ENTER})", False
XXXXXXX.Enabled=True

と、仕組めば判りやすいと思います。

投稿日時 - 2008-12-12 14:08:41

補足

回答ありがとうございます!
テキストボックスに入力されたデータが、自分のテーブルに反映されないうちは外部データベースへの保存処理を実行させない・・・確かにやりたいことはそういうことです。
それが行われていないから、こういうことになっているんだと思います。
自分のテーブルに書き込むデータがまだ残っている状態では、次の処理は実行させたくないですね。
私はの考えでは、処理は順々にスタックされて、先入先出されるものと思っていたのですが違うようですね・・・。
多分、こういうことになっているんだと思います。あくまで私の考えです。

1.ユーザがテキストボックスに書き込む
2.[内部処理]テキストボックス→フィールドに反映させようとしている
3.ユーザが外部データベースへの保存ボタンを押す
3A.[VBA]UPDATE [テーブル名] SET [コード] = 9
3B.[VBA]上記のSQLが実行されたテーブルを外部データベースへINSERT処理
4.処理完了

レコードの操作を行わないと、1、2が行われていないため、問題無く実行されます。
1を行うと2の内部処理が行われる。
その間(ユーザには分からない)に3の処理ボタンを押すと、
2の内部処理が実行中のため3Aが解決されず、3Bの処理だけが実行される。

すみません。質問の部分ではここまで書けませんでした。
2の処理が終了したことが分からないと3を実行させない。確かにそうしないとマズイですね。
その回避策として、別レコードを選択することで保存処理を確定させていました。
教えていただいた方法で保存させようとしましたが、状況は変わっていません。

投稿日時 - 2008-12-12 14:53:50

ANo.4

No.2です。
補足内容を見て、気づいたことがありましたので・・・

> Me![subform1].Setfocus

上記のコードですと、「subform1」というサブフォーム「コントロール」への
フォーカス移動になりますので、レコード保存の対象となるフォームは、
そのコントロールの親に当たる「Me」になってしまいます。

ですので、レコード保存の対象がサブフォームのレコードなのでしたら、

Me!subform1!ID.SetFocus

というように、サブフォーム内のコントロールを指定すれば、うまくいくかと
思います。


なお、No.3の方の回答にある、「DoMenuItem」は、Access2003のヘルプにも

> この引数に対して acMenuVer80 の設定値はありません。DoMenuItem
> メソッドを使って、Access 97 または Access 2000 のコマンドを表示する
> ことはできません。ただし、Visual Basic のコード内の既存の DoMenuItem
> メソッドは、引き続き動作します。表示するには、RunCommand メソッドを使います。

とあるように、Accessのバージョンへの依存性が高いため、お勧めしません。

投稿日時 - 2008-12-12 12:22:43

補足

なるほど・・・確かにフォームの指定だけだと駄目そうですね。
その場合なんですが、レコードであればどこでもいいのでしょうか?
複数(約10個)のテキストボックスを用意しており、それらを保存する予定です。
どれか、使用頻度の少ないものを指定しようかと思っているのですが・・・

投稿日時 - 2008-12-12 13:32:25

注意: {Shift}{Enter}を送出しても・・・。

確かに、VBAで{Shift}{Enter}を送出することで解決したかに・・・。
しかし、これは余りお勧めできません。

DoCmd.DoMenuItem acFormBar, acRecordsMenu, acSaveRecord, , acMenuVer70

などで当該レコードを保存が常道。

投稿日時 - 2008-12-12 09:15:38

お礼

Shift+Enterを押してから実行すると、確実に実行されます!
レコードを選択し直す以外に、ひとつ解決策が増えました。
ありがとうございます!

投稿日時 - 2008-12-12 13:32:18

ANo.2

> 成功時と失敗時の違いは、上記の通りフィールドを更新した直後に
> 違うレコードを選択するかしないかという事

【発生原因】
レコードの編集中は、保存されているレコードそのものではなく、
メモリ上にコピーされたデータを編集している形になっているようです。
(上記コマンドやレコード移動、フォームやテーブルを閉じるなどして
 レコードの保存が行われたときに、編集前のデータが、メモリ上の
 編集済みデータによって上書される)
そのため、レコード編集の保存前にSQL等で当該レコードを参照すると、
編集前のデータが返されることになります。

【回避方法】
SQLを走らせる前に、「DoCmd.RunCommand acCmdSaveRecord」で
レコードの保存を行って下さい。
(実行ボタンがメインフォームに、保存するレコードがサブフォームや
 別のフォームにある場合は、その前に「~.SetFocus」を使用して、
 保存対象にフォーカスを移動させてやる必要があります)

投稿日時 - 2008-12-12 08:38:19

補足

回答ありがとうございます!
保存させれば確かにうまくいきそうです。
Me![subform1].Setfocus
DoCmd.RunCommand acCmdSaveRecord
上記を追加してテストをしてみたのですが、動作的には以前と変わりませんでした。
・・・私が間違っているかもしれませんので、色々テストをしてみます。

投稿日時 - 2008-12-12 09:56:03

良くは判りませんが・・・。

もう一度、失敗するケースの操作要領を確認されたらと思います。
成功するケースでは、明らかに更新処理が完了しています。
が、失敗するケースでは、書かれている範囲では更新処理が完了しているのか不明。

実験1、{ENTER}を押してから保存処理を!
実験2、{SHIFT}{ENTER}を押してから保存処理を!

実験2と同じ操作をすると成功しているとは書かれています。

投稿日時 - 2008-12-11 17:25:57

お礼

回答ありがとうございます!
そんな方法があったのですね・・・
対象テーブルの更新処理が完了したかどうか?が争点になりそうです。

投稿日時 - 2008-12-12 09:44:29

あなたにオススメの質問