- ベストアンサー
Access VBA初心者のためのソフトリストとソフトの関連付け方法
- 初心者向けのAccess VBAで、テーブルT_ソフトリストとT_ソフトを使ってフォームF_入力のコンボボックスに関連するソフト名を表示する方法を教えてください。
- フォームF_入力のコンボボックスに使用者を入力すると、T_ソフトから使用者を探し、ソフトリストIDを取得し、そのIDを元にT_ソフトリストからソフト名を表示する方法を教えてください。
- Access VBAの初心者ですが、フォームF_入力のコンボボックスに入力した使用者に関連するソフト名を表示する方法が知りたいです。テーブルT_ソフトリストとT_ソフトを使って関連付けを行う方法を教えてください。
- みんなの回答 (19)
- 専門家の回答
質問者が選んだベストアンサー
遅くなりました。 (1) Combo_UserTypeの設定 集合タイプ テーブル/クエリ 値集合ソース T_使用者 列数 2 列幅 0cm,2cm 連結列 1 リスト幅 3cm (2) フォームのコード '######ここから######## Private Sub Combo_UserType_AfterUpdate() 'MsgBox Me!Combo_UserType.Column(0) Me!Combo_User.RowSource = "" Me!Combo_User.Requery Me!Combo_User.Value = "" '変数宣言 Dim db As Database Dim rs1 As Recordset Dim rs2 As Recordset Dim varSoft As String 'オブジェクト設定 Set db = CurrentDb Set rs1 = db.OpenRecordset("T_ソフトリスト", dbOpenDynaset) Set rs2 = db.OpenRecordset("T_ソフト", dbOpenDynaset) '検索開始 If rs2.RecordCount > 0 Then rs2.MoveFirst Do Until rs2.EOF 'データが見つかった時の処理 If CLng(Me!Combo_UserType.Column(0)) = CLng(rs2![使用者]) Then varSoft = DLookup("[ソフト名]", "T_ソフトリスト", "[ID] = " & rs2![ソフトリストID]) Combo_User_NotInList varSoft, acDataErrAdded End If rs2.MoveNext Loop End If rs1.Close: Set rs1 = Nothing rs2.Close: Set rs2 = Nothing db.Close: Set db = Nothing End Sub Private Sub Combo_User_NotInList(NewData As String, Response As Integer) If Me!Combo_User.RowSource = "" Then Combo_User.RowSource = NewData Else Combo_User.RowSource = Combo_User.RowSource & ";" & NewData End If Response = acDataErrAdded End Sub '######ここまで###### Combo_UserTypeの更新後では、いくつか変更しました。 (1) 「'データが見つかった時の処理」のコメント以下の2行。 もし、If文の中に入らないようであれば、 If CLng(Me.Combo_UserType.Column(0)) = CLng(rs2![使用者]) Then のように、両方、あるいはどちらか一方をCLngでキャストしてみて ください。たぶん、それで入ると思います。 (2) varSoft = DLookup("[ソフト名]", "T_ソフトリスト", "[ID] = " & rs2![ソフトリストID]) にしましたが、もとの varSoft = DLookup("[ソフト名]", "T_ソフトリスト", "[ID] = " & rs2![ソフトリストID] & "") でもデータは取れると思います。 (3) Me.Combo_UserType.Column(0) のようにして、コンボボックスでは名前を表示し、 非表示にしているIDをColumn(0)でコンボボックスの 列のインデックスで指定してIDを取得するように しました。 (4) 最初に抜けていたオブジェクトの後処理を最後に 追加しました。 たぶん、KtoTtoAさんが言われたキャストはCLng による型変換だろうと思います。。
その他の回答 (18)
- layy
- ベストアンサー率23% (292/1222)
>■初心者のよくある疑問・間違いや誤解 http://www.asahi-net.or.jp/~ef2o-inue/vba_k/sub04_200.html >マクロを「書いてみた」「動かした」「ダメでした」。 >よく、WebのExcelVBA関連の掲示板などで、 >初心者の方が他の質問の回答などを参考にして >マクロを作って動かしてみたものの、 >エラーになったり期待する結果でなかったりして、 >「なぜでしょうか」と質問を上げてくることがあります。 >そのマクロが自分で書いたものでも、 >Webサイトで見つけたものを変更したものでも、 >「マクロの記録」で作られたものであっても同じです。 >(記録したマクロは、最低限同じ環境で起動させないと同じ動作はしないばかりか、 >コードの記録パターンにある程度限りがあるので、 >そのままでも動かないケースもあるようです。) ということでコラムがあります。 VBAでもマクロでも同じです、回答をいかに有効に使うか。 回答はデタラメを教えているわけありません。 が、少なくとも「動かす前に」内容を確認してから、 同じことを自分の環境に実装する。 回答がどうであれ、 何がどうなっているか、を自分で考える過程も大事です。
お礼
ご指導、ご忠告有難うございます。 今回の質問の件は解決致しました。 ご忠告頂いたとおり、今後も自分で考え要点を整理しながら勉強していきたいと思います。
- layy
- ベストアンサー率23% (292/1222)
掲示板上はお互いが手探りで作っていく場でないでしょう。質疑応答、という域超えてます。 質問者は回答の要所だけに集中して自分の聞きたいことを進めたら良いです。 掲示板でコードを聞いたところで、どのくらい同じ環境状態かわかったものでない。そっくりそのまま稼動するとは思わない方が良いし、コピーするだけのやり方は上達遅い。掲示板の模範コードを期待できるのは中身が大丈夫と判断できるときでしょう。 今後のため 作業の進め方、これは見直しした方が良いです。こんな調子で進めたら今後も時間をロスします。 前述のように、整理してみること。要点つかんでますか?。 『エクセルでお仕事』 のサイトの VBAコラムをみること。
- nicotinism
- ベストアンサー率70% (1019/1452)
Debug.Print "ソフトリストID=" & rs2![ソフトリストID] とか Debug.Print "strSql=" & strSql を怪しげな変数を記述した後に加えて、イミディエイトウィンドウに 出てくる結果を検討されては? また長くなってきていますので整理するうえでも現状をもう一度アップされては? チャンと経緯を追ってのレスではありませんけど・・
- piroin654
- ベストアンサー率75% (692/917)
少し確認のため。 (1) Combo_Userは間違いなくコンボボックスですね。 リストボックスではないですね。 何故かというと、Selected(1)というプロパティ がコンパイルで引っかからないのはリストボックス以外に 考えられないからです。 (2) Accessのバージョンは何ですか。 (3) 提案のコードで、 If Nz(Combo_UserType) <> "" Then If (strSql = "") Then End Iff End If をコメントアウトして、、strSqlだけをコメント アウトしにままにするとどうですか。 (3) No10での、 If CLng(Me!Combo_UserType.Column(0)) = CLng(rs2![使用者]) Then varSoft = DLookup("[ソフト名]", "T_ソフトリスト", "[ID] = " & rs2![ソフトリストID]) CLngで型変換してもデータが表示されないということですね。 (4) 提示したコードに何か付け足したりして実行した、 ということではないですね。
- piroin654
- ベストアンサー率75% (692/917)
字数いっぱいだったので、つづきです。 提案のコードで、 Me!Combo_User.Column(1).Selected = True Me!Combo_User.Value = Me!Combo_User.ItemData(1) 設定したのは、Combo_Userに表示される データの数、たとえば表示されるソフト名を 一つにしたかったのか、あるいはsreSqlで取り込まれる 他のフィールドをソフト名だけにしたいので、 上記の設定をコード中にしたのか、いずれか だと思いますが、どちらでしょうか。 それと、Selectedについてはコードをコンパイル して、コンパイルが通るか確認してください。
補足
回答有り難うございます。 >「このフォームまたはレポートで指定されて >いる'(ソフト名)…'は存在しません。」 この件については、コードを貼り間違えていたようで、もう一度貼り直したら出来ました。失礼致しました。 Combo_Userの値集合タイプもコメントを頂いたように設定いたしました。コンパイル、実行が出来るようになったのですが、Combo_Userのコンボボックスに値が入らず、使用者を入力してもソフト名は空欄のコンボボックスが表示されてしまいます。 また、私が提案したコードでも同様の結果となってしまいました。 提案したコードのSelectedについてはコンパイルは通りました。以下2行については、参考にしたソースコードに記述されていたので、よく調べずに意味もなく使ってしまっていました。申し訳ございません。 Me!Combo_User.Column(1).Selected = True Me!Combo_User.Value = Me!Combo_User.ItemData(1)
- piroin654
- ベストアンサー率75% (692/917)
【エラーについて】 >「このフォームまたはレポートで指定されて >いる'(ソフト名)…'は存在しません。」 エラーの位置は varSoft = DLookup("[ソフト名]", "T_ソフトリスト", "[ID] = " & rs2![ソフトリストID]) のところですか。ここならば一応If文の中に入ったということですが。 varSoft = DLookup("[ソフト名]", "T_ソフトリスト", "[ID] = " & rs2![ソフトリストID]) を varSoft = DLookup("[ソフト名]", "T_ソフトリスト", "[ID] = " & rs2![ソフトリストID] & "") のように末尾に & "" を追加し、変更しても出ますか。 あるいは、デバッグ出来ない表示のみの場合も あるかもしれませんが、いずれにしても、 コード中のテーブル名やフィールド名に間違いがないか、 あるいは、IDなどがテーブルでは全角文字になっていないか 確認してみてください。また、コードの張り間違いが ないか確認してみてください。当然ながらコンパイル をしてみてください。 それと、No10の Combo_Userの設定については変更はありません。 としてのは、Combo_Userの値集合タイプは値リストとした ことに変更はない、と言う意味です。これも確認してください。 原因をかならず突きとめる必要があります。 【提案のコードについて】 この方法は、まさにコンボボックスの連動で、 No2(これは訂正する必要があるためNo13で対応してください) とNo13で述べたコンボボックスの値集合ソースを後から 指定しているだけのものです。したがって、SQLL文は 同じSQL文をつかいます。 そこでstrSqlを、 strSql = "SELECT T_ソフトリスト.ソフト名 " strSql = strSql & "FROM (T_ソフト INNER JOIN T_ソフトリスト ON T_ソフト.ソフトリストID = T_ソフトリスト.ID) INNER JOIN T_使用者 ON T_ソフト.使用者 = T_使用者.ID " strSql = strSql & "WHERE (((T_ソフト.使用者)=[Forms]![F_入力]![Combo_UserType]));" に置き換えてください。SQL文が長いのでstrSqlは 文を区切りながらstrSqlに取り込みます。 なお、各strSqlの""中の文の末尾は途中まで 半角開けてあることに留意してください。 【提案のコードについて】その2 Combo_User.RowSourceType = "Table/Query" Combo_User.RowSource = strSql Combo_User.Selected(1) = True Combo_User.Value = Combo_User.ItemData(1) Me!Combo_User.Requery まず、 Me!Combo_User.RowSourceType = "Table/Query" Me!Combo_User.RowSource = strSql Me!Combo_User.Selected(1) = True Me!Combo_User.Value = Combo_User.ItemData(1) のように、Meキーワードをつけてください。 本来は、この部分は、上記のstrSqlのSLECTのところで SELECT T_ソフトリスト.ソフト名 のように取得するデータを絞っているのでソフト名 だけが出てきます。したがって、 Me!Combo_User.RowSourceType = "Table/Query" Me!Combo_User.RowSource = strSql Me!Combo_User.Requery だけで、いいはずです。それから、 Combo_User.Selected(1) = True Combo_User.Value = Combo_User.ItemData(1) この部分についてですが、リストボックスには 複数選択のときに使用するSelectedプロパティ はありますが、コンボボックスにはないはずですが。 バージョンが違うと追加されたのですかね。 また、 Me!Combo_User.Value = Me!Combo_User.ItemData(1) はデータが複数ある場合にItemData(1)と設定すると Combo_Userに二番目のデータがすぐ表示される、 というこです。つまり、ソフト名が複数あると 二番目のソフトがすぐ表示されます。
- piroin654
- ベストアンサー率75% (692/917)
No10の Combo_Userの設定については変更はありません。 なお、Combo_UserTypeの表示で列幅を 0cm;2cm に設定していますが、 2cm;2cm にして、使用者IDが見える状態にしても 検索結果には影響はないので、そのように したい場合は列幅を変更してみてください。 コンボボックの連動の場合について、変更があります。 (1) Combo_Userの値集合ソースに設定するSQL文を以下に します。以下をコピーしてCombo_Userの値集合ソース に貼り付けます。 また、このSQL文を新しいクエリの SQLビューに貼り付け、デザインビューにしてテーブル間の 結合線、抽出条件、などを確認してみてください。 またこのクエリを実行してパラメータのフォームに 数値を入れるとソフト名が表示されます。 SELECT T_ソフトリスト.ソフト名 FROM (T_ソフト INNER JOIN T_ソフトリスト ON T_ソフト.ソフトリストID = T_ソフトリスト.ID) INNER JOIN T_使用者 ON T_ソフト.使用者 = T_使用者.ID WHERE (((T_ソフト.使用者)=[Forms]![F_入力]![Combo_UserType])); (2) Combo_UserTypeの値集合ソースはT_使用者です。 (3) フォームのコードは以下のままで、変更はありません。 Private Sub Combo_UserType_AfterUpdate() Me!Combo_User.Requery End Sub Private Sub Combo_UserType_Change() Me!Combo_User.Value = "" Me!Combo_User.Requery End Sub コンボの連動は将来使うことが出てくる可能性が 高いので、この際に中身を観察してみてください。 わからないことがあれば補足してください。
補足
コメントが遅くなり申し訳ございません。 多数のコメント、丁寧な解説有り難うございます。 NO.10でコメントを頂いた様に書いてみたのですが、 「このフォームまたはレポートで指定されている'(ソフト名)…'は存在しません。」 と出てしまいました。 コンボの連動についてはご指導頂いたとおりやってみました。 今後に活かすことができそうな便利な物なので使いこなせるように勉強したいと思います。 本題の質問の方ですが、自分でもソースコードを考えて作ってみたのですが、これではソフト名が全て出てしまいうまくいきませんでした。 新たな質問になってしまいますが、SELECT文でフォームで使用者を入力し、ソフト名を取得することは出来るでしょうか? お願い致します。 Private Sub Combo_UserType_AfterUpdate() Dim strSql As String Dim strSql2 As String Combo_UserType.SetFocus If Nz(Combo_UserType) <> "" Then If (strSql = "") Then strSql = "SELECT T_ソフトリスト.ID, T_ソフトリスト.ソフト名, T_ソフト.使用者 ,T_ソフト.ソフトリストID FROM T_ソフト, T_ソフトリスト WHERE T_ソフト.使用者 = " & Combo_UserType & ";" End If End If Combo_User.RowSourceType = "Table/Query" Combo_User.RowSource = strSql Combo_User.Selected(1) = True Combo_User.Value = Combo_User.ItemData(1) Me!Combo_User.Requery End Sub
- layy
- ベストアンサー率23% (292/1222)
解決へ向かっているようで、そうでないなら、当初の疑問が残っているならはっきりしましょう。 いっぱい書かれてもわからないとかレベル高すぎるとか。まだ試行錯誤しているとなると、コンボボックスの使い方から確認した方がいいのでは?。 コンボの表示ネタはどこで定義するか、表示列の制御は、とか基本的なところ。 コードみたままやれば、やりたいことは実現でしょうが、KNOW-HOW、テクニック、得るものが少ないのはもったいない。 どちらかと言えばこちらのが後から役に立つものです。 最悪なのは、結果が出たから質問締める。結果が出たが自分では何もできない、そこで、また同じような質問をする。その繰り返し。 ステップアップできてないことでしょうね。 ここらで、整理してみては?
補足
回答有り難うございます。 試行錯誤と言うのは、自分でも考えてソースコードを書いてみていたので「試行錯誤」という言葉を使わせていただきました。誤解を招くような言い方をしてしまい、申し訳ございません。 頂いたコメントのご指摘、ご指導を元に自分でも考えて勉強させて頂いています。
- piroin654
- ベストアンサー率75% (692/917)
コンボボックスを連動させる例では、 Q使用者をT使用者に変更し、Combo_User の値集合ソースのT_ソフトとT使用者の 結合線をT_ソフトの使用者とT_使用者の IDに設定します。
- layy
- ベストアンサー率23% (292/1222)
自己解決できる方向に進んでいますか?。 作ってもらうのを待っていませんか?。 >どの様なソースコードを書けばよいでしょうか? 解決でしょうか?。 参考で。 http://www.accessclub.jp/ http://www.mahoutsukaino.com/
補足
ご指摘有難うございます。 アドバイスを参考に自分でも試行錯誤しながら考えていますが、まだ解決しておりません。 コメントを頂いたHPも参考に頑張ってみます。
- 1
- 2
お礼
回答有り難うございます。 当方の不手際で、列幅を修正するのを忘れていました。申し訳ございませんm(__)m これを修正したところ思ったとおりの動作致しました。 何度も丁寧な解説、ご指導ありがとうございました。