- ベストアンサー
【Access】 VBA 入力漏れを防ぎたい
Access&VBA初心者です。 商品の入出庫状況をACCESSで管理しようとしています。 ある項目の入力漏れを防ぐためにメッセージが出るようにしたいのですがどのようにしたらいいかわかりません。 【商品マスターテーブル】 商品コード 商品名 管理・・・yes/no型(yesの場合はロットと期限の管理が必要) 【入力フォーム】 商品コード 入庫数 出庫数 ロット 期限(タブストップしない) 商品マスタで「管理」がYesになっている場合で「ロット」もしくは「期限」が入力されていない場合、 次のレコードに移る前に「ロット又は期限が入力されていません」というメッセージボックスを表示し、 「ロット」と「期限」を入力するようにしたいと思っています。 現在はネットで調べて「ロット」を入力したら「期限」を入力するように Private Sub ロット_AfterUpdate() If IsNull(Me.期限) Then MsgBox "期限を確認してください" Me.期限.SetFocus End If End Sub というかんじにしてみたのですが、 「ロット」を入力し忘れてしまったり、「管理」がNoであっても「ロット」を入力することがあるので 改善をしたいと思っていますがVBAの使い方がわからないためこの先にすすめません。 何か良い方法がありましたらアドバイスをお願いします。 ※入力フォームにはテキストボックスを貼り付けて「管理」が-1もしくは0で表示だけされるようにしています。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
- ベストアンサー
商品マスターの情報に基づいて入力するフィールドを制限する仕組みと未入力チェックを組み合わせ、かつ、レコードを登録する際にチェック機能を起動するのが最適。 しかし、これには、全体のイベントの意味やそれぞれの仕掛けの相互関連の理解が課題。 少し、難しいかも知れませんね。 <Dlookup関数> ? DBLookup("管理", "商品マスター", "商品コード='A-102'",False) False ? DBLookup("管理", "商品マスター", "商品コード='A-102'","Not Found!") Not Found! ? DLookup("管理", "商品マスター", "商品コード='A-102'") Null ? Nz(DLookup("管理", "商品マスター", "商品コード='A-102'"),False) False ところで、このように Access の DLookup関数は、Null値を返します。 ですから、Nz関数を併用するかDBLookup関数を使う必要があるかも知れません。 なぜなら、 DBLookup関数はNull値の置換を指示することが可能だからです。 なお、DBLookup関数の類は自作することになります。 さて、入力するフィールドを制限する仕組みを前提にしない場合のチェックコードは僅か5行。 ここでは、未入力か否かをフィールドに入力されている値+""の長さが0か否かで判断しています。 ここら辺りは好みの問題です。 Private Sub Form_AfterUpdate() If Nz(DLookup("管理", "商品マスター", "ID=" & Me.商品マスター_ID), False) Then If Not Len(Me.ロット & Me.期限 & "") Then MsgBox "[ロット]ないし[期限]が未入力です。", vbExclamation, " 警告" End If End If End Sub Private Sub Form_AfterUpdate() If DBLookup("管理", "商品マスター", "商品コード='" & Me.商品コード & "'"), False) Then If Not Len(Me.ロット & Me.期限 & "") Then MsgBox "[ロット]ないし[期限]が未入力です。", vbExclamation, " 警告" End If End If End Sub さて、確かに僅か5行程度のコードで目的は達成されると思います。 しかし、これじゃ、管理不要の場合の入力の有無チェックをしなきゃ片手落ち。 Private Sub Form_AfterUpdate() If Nz(DLookup("管理", "商品マスター", "ID=" & Me.商品マスター_ID), False) Then If Not Len(Trim(Me.ロット & Me.期限) & "") Then MsgBox "[ロット]ないし[期限]が未入力です。", vbExclamation, " 警告" End If Else If Len(Trim(Me.ロット & Me.期限) & "") Then MsgBox "[ロット]と[期限]の不要データをクリアします。", vbInformation, " お知らせ" Me.ロット = Null Me.期限 = Null End If End If End Sub そういうことで、先の5行を多少修正することになります。 しかし、これで、現場のユーザが納得するかどうかです。 「そもそも入力が必要の無いフィールドを無効にしてくれないか?」と言い出すかもしれません。 こうして、徐々に先の回答へと回帰していきます。 しかし、それさえも使い勝手の問題で否定されるでしょう。 このように、VBAでの入力の制御は、実に色んな問題を孕んでいます。 肝心なのは、終始一貫したルールを全ての入力フォームに適用することです。 質問者は、その探求の入り口に立ったばかり。 頑張って下さい。
その他の回答 (4)
- mshr1962
- ベストアンサー率39% (7417/18945)
Private Sub 詳細_AfterUpdate() KR = Dblookup("管理","商品マスタ","[商品コード]=" & Me.商品コード) If KR = VbYes Then If IsNull(Me.ロット) Or IsNull(Me.期限) Then MsgBox "ロット又は期限が入力されていません" If IsNull(Me.ロット) Then Me.ロット.SetFocus Else Me.期限.SetFocus End If End If End If End Sub
補足
ご回答ありがとうございます。 そのまま貼り付けてみたのですがなぜか何もおこりません。 勉強不足で大変申し訳ないのですが KR = Dblookup("管理","商品マスタ","[商品コード]=" & Me.商品コード) の部分の解説をしていただけると助かります。 入力した商品コードを元に"商品マスタ"の"管理"を見る?ということでしょうか。 あとPrivate Sub 詳細_AfterUpdate()とは 新しいレコードに移る前にメッセージboxが表示されるようになるということでしょうか。 詳細プロパティのイベントタブでみることはできますか? 本当に初心者な質問な上、質問の内容もよくわからなくて申し訳ありません。
- tarinko_06
- ベストアンサー率24% (15/62)
すいませんNo2で回答したものです。 よく確認してませんでした。入力した段階でもうチェックしてるんですね。 入力系をチェックするならいちいちその都度きくよりも 最後にまとめてチェックする方が親切ですよ。 ネットなんかで登録する時も最後の決定ボタン押した時に 間違ってますよ~て注意してくるじゃないですか。
- tarinko_06
- ベストアンサー率24% (15/62)
管理がYESかNOのどっちなのかは、表示されてる-1,0で判断するって事ですか? もしそうなら下の方法で良いと思います。 もし管理の値をまだ取得していないなら 商品コードをキーにしてADOやDAOでチェックしてあげれば良いです。 ???にはテキストボックスの名前、-1がYes,0がNoと考えてます。 Private Sub ロット_AfterUpdate() If Me!??? = -1 then If IsNull(Me.期限) or IsNull(Me.ロット) Then MsgBox "ロット又は期限が入力されていません" Me.期限.SetFocus End If End If End Sub
お礼
ご回答ありがとうございます。 ロットの更新後処理→フォーカス喪失時にしてみたところ うまくメッセージボックスが表示されました。 エクセルのIF関数と違うのでIFの使い方がわからなくて困っていたのですが、疑問が解決されました。 ただ、メッセージボックス表示後フォーカスの移動がうまいこといかなかったので検討の上、後日会社で再度試してみようと思います。
商品マスター: ID__商品コード__品名___________管理 1___A-101________OO-OOO___No 2___B-121________XX-XXX_____Yes 入出庫履歴: ID__入出庫区分__商品マスター_ID__数量_____ロット 期限 1_________________1_____________________1_______10_______0 2_________________1_____________________2_______10_______0 3_________________2_____________________1_________5_______0 4_________________2_____________________2_________5_______0 まず、列[入出庫区分]を設けた方が良いかも知れません。 1=入庫、2=出庫、3=調節、9=その他 将来、棚卸誤差等の調節等の入力が必要になった場合の対応が容易です。 ID__入出庫区分__商品マスター_ID__数量__ロット__期限 1_____________入庫__A-101________________10_______0 2_____________入庫__B-121________________10_______0 3_____________出庫__A-101__________________5_______0 4_____________出庫__B-121__________________5_______0 ところで、質問の回答はちょっとややこしいです。 つまり、どのように仕掛けるかという工夫の問題だからです。 例えば、商品マスターの情報に応じて入力フィールドの有効・無効を設定するのも手。 この場合、有効なフィールドが入力されているか否かをテストすれば良いことに。 その場合、既存レコードの設定もしなきゃおかしな現象になります。 また、有効・無効で変更できなくなる列の初期化も忘れてはいけません。 以上のようなことを実現するサンプルコードは次のようです。 Private Sub Form_Current() If Not Me.NewRecord Then SetEnabled Me.商品マスター_ID End If End Sub Private Sub Form_AfterUpdate() Dim ctl As Control For Each ctl In Me.Controls If ctl.ControlType = acTextBox Or ctl.ControlType = acComboBox Then If ctl.Enabled And (Len(ctl.Value & "") = 0) Then Warning ctl.name & " が未入力です!" Exit For End If End If Next ctl End Sub Private Sub 商品マスター_ID_LostFocus() Dim lngGoodsID As Long lngGoodsID = Val(Me.商品マスター_ID & "") SetEnabled Me.商品マスター_ID If lngGoodsID = 0 Then Message "商品コードを選択して下さい!" End If End Sub Private Sub SetEnabled(ByVal lngGoodsID As Long) Dim isKanri As Boolean isKanri = (DLookup("管理", "商品マスター", "ID=" & lngGoodsID) = True) Me.ロット.Enabled = isKanri Me.期限.Enabled = isKanri If Not isKanri And Len(Me.ロット & Me.期限 & "") Then Me.ロット = Null Me.期限 = Null End If End Sub <標準モジュール> Public Sub Message(ByVal Msg As String) MsgBox Msg, vbInformation, " お知らせ" End Sub Public Sub Warning(ByVal Msg As String) MsgBox Msg, vbExclamation, " 警告" End Sub Q、何か良い方法がありましたらアドバイスをお願いします。 A、入力フォームを閉じた時に、不具合レコードをチェックし警告・削除することです。 上述のような警告システムはユーザの自在な入力を阻害するだけです。
お礼
ご回答ありがとうございます。 なにぶん初心者というかVBAを全く知らないまま質問をしてしまったものでコードの解読に少し時間がかかりそうです。 参考にさせていただきます。
お礼
丁寧なご回答ありがとうございます。 やはり奥が深いというか難しいのですね。 >全体のイベントの意味やそれぞれの仕掛けの相互関連の理解が課題 まさにおっしゃる通りです。 今回は前任者が紙ベースで管理していたものをデータベース上での管理に変更しようとしたのが始まりだったので、 今後私から後任者に引き継ぎをする前までに使い勝手のよいものを作成していこうと思います。