★★★★★★Excel2000VBA独学~★★★★★★ 『 SQL の学習用 』の続き ★★★★★★~ 「パラメータクエリ」を使って、ドロップダウンを段階的に絞り込む実験~
  
※まだ書きかけです。すみません。
※間違ってたらすみません。
※メモ書きなので、自分でも意味不明な箇所も多いです。ごめんなさい。

  

ファイル名やフルパスが変わると正常動作しなくなるようなのでやったらダメ。
それでもあえてやりたい場合は、以下の通り。

https://euc-access-excel-db.com/tips/ct07_se/ct075012_xls2k_vba_tips/odbc-miquery-make01
のサンプルを使います。

サンプルのダウンロード

このサンプルの、Sheet1に以下のようなリスト表を作った場合です。
(以下をテキストファイルにコピペ後、スペースをTABに置換してExcelのA1セルの位置にコピペします。)

大分類 中分類 小分類 小々分類
A a あ イ
A a あ ロ
A a い ハ
A b う ニ
A b え ホ
A b え ヘ
B c お ト
B c お チ
B c か リ
B d き ヌ
B d く ル
B d く ヲ
C e け ワ
C e け カ
C e こ ヨ
C f さ タ
C f さ レ
C f し ソ
A g ほ にゃ
A g ほ にゅ
A g ほ にゅ
A g ほ ひょ
A g hi ma
A g hi ru
A g hi mo
A g hi nn

=====================================

Sheet2モジュールに以下のコードをコピペ

============================================================

●「シート上の既存の複数のQyeryTableオブジェクト」を「削除しない」ためのコードの書き換え

MSQryOnlMakeByODBCFunc001()の、
「シート上の既存のQyeryTableオブジェクトを削除する部分のブロック」をコメントアウトする。
以下の部分。

'すでにあるQueryTableオブジェクトを処理する
If 1 <= o_ImpWSht01jj.QueryTables.Count Then o_ImpWSht01jj.QueryTables(1).Delete ' o_ImpWSht01jj.Cells.ClearContents o_ImpWSht01jj.Rows.Delete 'いったんQueryTableオブジェクトを削除。 '紐ついている名前定義も一緒に消去されます。 Else End If Sheet2モジュールの場合は、test02()を以下のように書き変える。 別の少し右側に新しいQueryTableオブジェクトを生成するために。 吸い込みシートを「自ファイル」の「目的のシート」に設定。 '他ファイルデータの吸込み用設定 s_TrgFNm001jj = "D:\1\test98.xlsm" '外部の、吸い込みたい先のファイル s_TrgFoldPath001jj = "D:\1" 'そのファイルが在るフォルダ Set o_ImpSht001jj = Worksheets("Sheet×××") 'このファイルの中の、QTオブジェクトを生成したいシート(オブジェクト) s_ImpCelAddr001jj = "$A$1" 'そのシートのQTオブジェクトを生成したいセル位置 を '他ファイルデータの吸込み用設定 s_TrgFNm001jj = "D:\1\自ファイル名.xlsm" '外部の、吸い込みたい先のファイル s_TrgFoldPath001jj = "D:\1" 'そのファイルが在るフォルダ Set o_ImpSht001jj = Worksheets("Sheet×××") 'このファイルの中の、QTオブジェクトを生成したいシート(オブジェクト) s_ImpCelAddr001jj = "$×××$1" 'そのシートのQTオブジェクトを生成したいセル位置 に。 「o_ImpSht001jj.Range("A1").Select」を 「o_ImpSht001jj.Range(s_ImpCelAddr001jj).Select」に書き変え。 「s_SqlStr01jj = "SELECT * FROM Sheet1$"」を
「s_SqlStr01jj = "SELECT * FROM [Sheet2$xxxxxxx]"」に書き変え

===================================

Webから「CangeQramQueryOnePrm01()」をコピペ。
https://euc-access-excel-db.com/tips/ct07_se/ct075012_xls2k_vba_tips/odbc-miquery-make01#lbl_1311
のコード。

「パラメータのデータ型」の「xlParamTypeChar」はそのまま。数値型などのほかのデータ型に変えたかったら、
Parameters.Addメソッドのヘルプの、「XlParameterDataType 列挙」のリンクに書いてあります。

===================================

上記の「CangeQramQueryOnePrm01()」のコードのSQL部分を書き変え。

「Sheet2用」にするために、
「Set qt = Worksheets("sheet1").QueryTables(1)」を
「Set qt = Worksheets("sheet2").QueryTables(1)」に書き変え。目的のシート名に変えます。

既存のSQLに、『「大分類」などの列にパラメータを使うよ 』というだけの設定を追加する。
「(具 Like ?)」を
「(大分類 Like ?)」や「(中分類 Like ?)」など、その時々に応じて書き換え。

パラメータの具体的な設定。
「s_PrmNm1 = "具Prm"」を
「s_PrmNm1 = "Prm大分類"」に書き変え。(パラメータ名の設定)

「Set o_ParamRange1 = Worksheets("sheet1").Range("G2") 」を
「Set o_ParamRange1 = Worksheets("sheet2").Range("G1") 」に。パラメータにしたいセル位置の指定。シート名を間違えないようにする。

「o_ParamRange1.Offset(0, 1).Value = "具Prm"」を
「o_ParamRange1.Offset(0, 1).Value = "大分類"」に。パラメータにしたいセルの右に、どの列をパラメータにしたかが分かりやすいように列名を入れる。

実行。

このコードは、1つのQueryTableオブジェクトに対して何回でも実行できるので、
もし、「Set o_ParamRange1 = Worksheets("sheet2").Range("G1") 」を書き間違えたら、
正しく修正して再度実行。

===================================

実際にセルにパラメータの値を入力して、絞り込みがちゃんと行われるかをチェック。
「%」を入れると全部表示される。(ExcelのSQLでは「%」が「ALL」の意味のワイルドカードなのd。)

※ただし、この時点ですでに、ファイルを再起動すると、ファイルが開く速度が遅くなります。
再計算の設定を「手動」に変えてもだめです。パラメータの値が空でもダメです。
何か遅くならない設定を見つけないといけないかもです。
ただ、パラメータの数が20個でも30個でも同じ速度で開くなら、許容範囲かもしれません。

===================================

2つめのQyeryTableオブジェクトの作成

「test02()」プロシージャの以下の部分を書き変え

「s_ImpCelAddr001jj = "$A$1"」を
「s_ImpCelAddr001jj = "$j$1"」に。そのシートのQTオブジェクトを生成したいセル位置を変更。シート名は同一シートなので、変更しなくていい。

「s_ChkQTobjNm01jj = "QTSht02"」を
「s_ChkQTobjNm01jj = "QTSht03"」に。新しく作るので、新しい名前にする。

同一シートの、ソースにしたいQueryTableオブジェクトの名前を指定します。
例えば、
「s_SqlStr01jj = "SELECT * FROM [Sheet2$xxxxxxx]"」を
「s_SqlStr01jj = "SELECT * FROM [Sheet2$QTSht02]"」に。
イミディエイトで
「? Worksheets("Sheet2").QueryTables(1).name」や
「? Worksheets("Sheet2").QueryTables(2).name」や
「? Worksheets("sheet2").QueryTables(××).sql」などをやって、
1つ古いQueryTableオブジェクトの名前を指定します。
基本、「? Worksheets("Sheet2").QueryTables(1)」が最新の(最後に作った)QueryTableオブジェクトの名前です。

なので、
現在1つのQueryTableオブジェクトがあるなら、「? Worksheets("Sheet2").QueryTables(1)」が、
2つのQueryTableオブジェクトがあるなら、「? Worksheets("Sheet2").QueryTables(2)」が、
3つのQueryTableオブジェクトがあるなら、「? Worksheets("Sheet2").QueryTables(3)」が、
「1つ前のQueryTableオブジェクトの名前」ということになります。
「QueryTables(××)」の数字を既存のQueryTableオブジェクトの個数以上に指定すると、
「インデックスが有効範囲に無い」というエラーになります。
繰り返しますが、「? Worksheets("sheet2").QueryTables(××).sql」などでも確認できます。

このあと、「test02」を実行します。

最初のQyeryTableオブジェクトの右側に、それをソースにしたQyeryTableオブジェクトが出来ます。

===================================================

上記の「CangeQramQueryOnePrm01()」のコードのSQL部分を書き変え。

「Sheet2用」にするために、
「Set qt = Worksheets("sheet1").QueryTables(1)」を
「Set qt = Worksheets("sheet2").QueryTables(1)」に書き変え。目的のシート名に変えます。

※↑「QueryTables(1)」は最新のQueryTableオブジェクトを意味するので、そこの数字は変えなくてOKです。
いちおうこの時点だと、
「? Worksheets("sheet2").QueryTables(2).sql」で1つ前のQyeryTableオブジェクトのSQLがわかります。
SELECT * FROM [Sheet1$] WHERE (大分類 Like ?)

「? Worksheets("sheet2").QueryTables(1).sql」だと最新のQueryTableオブジェクトのSQL。
SELECT * FROM [Sheet2$QTSht02]

SQLのソースとなるテーブルを最新のQyeryTableオブジェクトの名前に書き変える。
s_SQLStr01 = ""
s_SQLStr01 = s_SQLStr01 & "SELECT"
s_SQLStr01 = s_SQLStr01 & " *"
s_SQLStr01 = s_SQLStr01 & " FROM"
s_SQLStr01 = s_SQLStr01 & " [Sheet2$QTSht02]" ←←←←←ココ。
s_SQLStr01 = s_SQLStr01 & " WHERE"
s_SQLStr01 = s_SQLStr01 & " (大分類 Like ?)"

上記のSQLに、『「中分類」の列にパラメータを使うよ 』というだけの設定を追加する。
「(大分類 Like ?)」を「(中分類 Like ?)」に書き換え。

パラメータの具体的な設定。
「s_PrmNm1 = "Prm大分類"」を
「s_PrmNm1 = "Prm中分類"」に書き変え。(パラメータ名の設定)

「Set o_ParamRange1 = Worksheets("sheet1").Range("G2") 」を
「Set o_ParamRange1 = Worksheets("sheet2").Range("P1") 」に。パラメータにしたいセル位置の指定。シート名を間違えないようにする。

「o_ParamRange1.Offset(0, 1).Value = "大分類"」を
「o_ParamRange1.Offset(0, 1).Value = "中分類"」に。パラメータにしたいセルの右に、どの列をパラメータにしたかが分かりやすいように列名を入れる。

実行。

このコードは、1つのQueryTableオブジェクトに対して何回でも実行できるので、
もし、「Set o_ParamRange1 = Worksheets("sheet2").Range("P1") 」を書き間違えたら、
正しく修正して再度実行。

===================================

実際にセルに中分類の列のパラメータの値を入力して、絞り込みがちゃんと行われるかをチェック。
「%」を入れると全部表示される。(ExcelのSQLでは「%」が「ALL」の意味のワイルドカードなのd。)

※念のため、ここまでの状態を上書きして、ファイルを再起動。

===================================

入力規則(データタブ→データの入力規則アイコン)で、ドロップダウンリストを作ります。

大分類のリスト内容は手書きで「大分類,A,B,C,%」で。

中分類のリスト内容は、大分類を「%」で全表示させた状態で、
最初のQueryTableオブジェクトの「中分類」の列を、
ドラッグで縦に、普通に範囲指定。
このとき、1行目の列名も含めて選択します。リストが1行だった場合、次回にリストが1行しか表示されなくなってしまうため。
(列名を選んでもエラーにならず、自段階のリストが空白になるだけなので心配はいりません)
リスト自体は「同じ値が自動的にグループ化されて」空白行も字度的に無くなり、ドロップダウンリストに表示されるようになります。

※同左を確認出来たら、再度、念のため、ここまでの状態を上書きして、ファイルを再起動。
パラメータが増えてもファイルを開く速度の遅さは変わらないことをチェック。

===================================

3つめのQyeryTableオブジェクトの作成

「test02()」プロシージャの以下の部分を書き変え

「s_ImpCelAddr001jj = "$A$1"」を
「s_ImpCelAddr001jj = "$t$1"」に。そのシートのQTオブジェクトを生成したいセル位置を変更。シート名は同一シートなので、変更しなくていい。

「s_ChkQTobjNm01jj = "QTSht03"」を
「s_ChkQTobjNm01jj = "QTSht04"」に。新しく作るので、新しい名前にする。
間違わないように、事前に、数式タブの「名前の管理」でもチェックできます。
(完全に同一のものかどうかは不明ですが。QueryTableオブジェクト名と同じ名前の管理になるんですかね???)
そこにあるものを同じ名前を使わないようにします。

同一シートの、ソースにしたいQueryTableオブジェクトの名前を指定します。(今回の事例では1つ前のもので。)
例えば、
「s_SqlStr01jj = "SELECT * FROM [Sheet2$QTSht02]"」を
「s_SqlStr01jj = "SELECT * FROM [Sheet2$QTSht03]"」に。
イミディエイトで
「? Worksheets("Sheet2").QueryTables(1).name」や
「? Worksheets("Sheet2").QueryTables(2).name」や
「? Worksheets("sheet2").QueryTables(××).sql」などをやって、
1つ古いQueryTableオブジェクトの名前を指定します。
基本、「? Worksheets("Sheet2").QueryTables(1)」が最新の(最後に作った)QueryTableオブジェクトの名前です。
なので、
現在1つのQueryTableオブジェクトがあるなら、「? Worksheets("Sheet2").QueryTables(1)」が、
2つのQueryTableオブジェクトがあるなら、「? Worksheets("Sheet2").QueryTables(2)」が、
3つのQueryTableオブジェクトがあるなら、「? Worksheets("Sheet2").QueryTables(3)」が、
「1つ前のQueryTableオブジェクトの名前」ということになります。
「QueryTables(××)」の数字を既存のQueryTableオブジェクトの個数以上に指定すると、
「インデックスが有効範囲に無い」というエラーになります。
繰り返しますが、「? Worksheets("sheet2").QueryTables(××).sql」などでも確認できます。

このあと、「test02」を実行します。

最初のQyeryTableオブジェクトの右側に、それをソースにしたQyeryTableオブジェクトが出来ます。

===================================================

上記の「CangeQramQueryOnePrm01()」のコードのSQL部分を書き変え。

「Sheet2用」にするために、
「Set qt = Worksheets("sheet1").QueryTables(1)」を
「Set qt = Worksheets("sheet2").QueryTables(1)」に書き変え。目的のシート名に変えます。

※↑「QueryTables(1)」は最新のQueryTableオブジェクトを意味するので、そこの数字は変えなくてOKです。
いちおうこの時点だと、
「? Worksheets("sheet2").QueryTables(2).sql」で1つ前のQyeryTableオブジェクトのSQLがわかります。
SELECT * FROM [Sheet1$] WHERE (大分類 Like ?)

「? Worksheets("sheet2").QueryTables(1).sql」だと最新のQueryTableオブジェクトのSQL。
SELECT * FROM [Sheet2$QTSht02]

SQLのソースとなるテーブルを最新のQyeryTableオブジェクトの名前に書き変える。
s_SQLStr01 = ""
s_SQLStr01 = s_SQLStr01 & "SELECT"
s_SQLStr01 = s_SQLStr01 & " *"
s_SQLStr01 = s_SQLStr01 & " FROM"
s_SQLStr01 = s_SQLStr01 & " [Sheet2$QTSht03]"←←←←←ココ。
s_SQLStr01 = s_SQLStr01 & " WHERE"
s_SQLStr01 = s_SQLStr01 & " (中分類 Like ?)"

上記のSQLに、『「小分類」の列にパラメータを使うよ 』というだけの設定を追加する。
「(中分類 Like ?)」を「(小分類 Like ?)」に書き換え。

パラメータの具体的な設定。
「s_PrmNm1 = "Prm中分類"」を
「s_PrmNm1 = "Prm小分類"」に書き変え。(パラメータ名の設定)

「Set o_ParamRange1 = Worksheets("sheet1").Range("G2") 」を
「Set o_ParamRange1 = Worksheets("sheet2").Range("z1") 」に。パラメータにしたいセル位置の指定。シート名を間違えないようにする。

「o_ParamRange1.Offset(0, 1).Value = "中分類"」を
「o_ParamRange1.Offset(0, 1).Value = "小分類"」に。パラメータにしたいセルの右に、どの列をパラメータにしたかが分かりやすいように列名を入れる。

実行。

このコードは、1つのQueryTableオブジェクトに対して何回でも実行できるので、
もし、「Set o_ParamRange1 = Worksheets("sheet2").Range("z1") 」を書き間違えたら、
正しく修正して再度実行。

===================================

入力規則(データタブ→データの入力規則アイコン)で、ドロップダウンリストを作ります。

中分類のリスト内容は、
2つめのQueryTableオブジェクトにて、中分類で一番少ないリスト数のものを表示させたうえで、
2つめのQueryTableオブジェクトの「小分類」の列を、
ドラッグで縦に、普通に範囲指定。
このとき、1行目の列名も含めて選択します。リストが1行だった場合、次回にリストが1行しか表示されなくなってしまうため。
(列名を選んでもエラーにならず、自段階のリストが空白になるだけなので心配はいりません)
リスト自体は「同じ値が自動的にグループ化されて」空白行も字度的に無くなり、ドロップダウンリストに表示されるようになります。

※同左を確認出来たら、再度、念のため、ここまでの状態を上書きして、ファイルを再起動。
パラメータが増えてもファイルを開く速度の遅さは変わらないことをチェック。

===================================

4つめののQyeryTableオブジェクトの作成

「test02()」プロシージャの以下の部分を書き変え

「s_ImpCelAddr001jj = "$z$1"」を
「s_ImpCelAddr001jj = "$ad$1"」に。そのシートのQTオブジェクトを生成したいセル位置を変更。シート名は同一シートなので、変更しなくていい。

「s_ChkQTobjNm01jj = "QTSht04"」を
「s_ChkQTobjNm01jj = "QTSht05"」に。新しく作るので、新しい名前にする。
間違わないように、事前に、数式タブの「名前の管理」でもチェックできます。
(完全に同一のものかどうかは不明ですが。QueryTableオブジェクト名と同じ名前の管理になるんですかね???)
そこにあるものを同じ名前を使わないようにします。

同一シートの、ソースにしたいQueryTableオブジェクトの名前を指定します。(今回の事例では1つ前のもので。)
例えば、
「s_SqlStr01jj = "SELECT * FROM [Sheet2$QTSht03]"」を
「s_SqlStr01jj = "SELECT * FROM [Sheet2$QTSht04]"」に。
イミディエイトで
「? Worksheets("Sheet2").QueryTables(1).name」や
「? Worksheets("Sheet2").QueryTables(2).name」や
「? Worksheets("sheet2").QueryTables(××).sql」などをやって、
1つ古いQueryTableオブジェクトの名前を指定します。
基本、「? Worksheets("Sheet2").QueryTables(1)」が最新の(最後に作った)QueryTableオブジェクトの名前です。
なので、
現在1つのQueryTableオブジェクトがあるなら、「? Worksheets("Sheet2").QueryTables(1)」が、
2つのQueryTableオブジェクトがあるなら、「? Worksheets("Sheet2").QueryTables(2)」が、
3つのQueryTableオブジェクトがあるなら、「? Worksheets("Sheet2").QueryTables(3)」が、
「1つ前のQueryTableオブジェクトの名前」ということになります。
「QueryTables(××)」の数字を既存のQueryTableオブジェクトの個数以上に指定すると、
「インデックスが有効範囲に無い」というエラーになります。
繰り返しますが、「? Worksheets("sheet2").QueryTables(××).sql」などでも確認できます。

このあと、「test02」を実行します。

最初のQyeryTableオブジェクトの右側に、それをソースにしたQyeryTableオブジェクトが出来ます。

===================================================

上記の「CangeQramQueryOnePrm01()」のコードのSQL部分を書き変え。

「Sheet2用」にするために、
「Set qt = Worksheets("sheet1").QueryTables(1)」を
「Set qt = Worksheets("sheet2").QueryTables(1)」に書き変え。目的のシート名に変えます。

※↑「QueryTables(1)」は最新のQueryTableオブジェクトを意味するので、そこの数字は変えなくてOKです。
いちおうこの時点だと、
「? Worksheets("sheet2").QueryTables(2).sql」で1つ前のQyeryTableオブジェクトのSQLがわかります。
SELECT * FROM [Sheet1$] WHERE (大分類 Like ?)

「? Worksheets("sheet2").QueryTables(1).sql」だと最新のQueryTableオブジェクトのSQL。
SELECT * FROM [Sheet2$QTSht02]

SQLのソースとなるテーブルを最新のQyeryTableオブジェクトの名前に書き変える。
s_SQLStr01 = ""
s_SQLStr01 = s_SQLStr01 & "SELECT"
s_SQLStr01 = s_SQLStr01 & " *"
s_SQLStr01 = s_SQLStr01 & " FROM"
s_SQLStr01 = s_SQLStr01 & " [Sheet2$QTSht04]"←←←←←ココ。
s_SQLStr01 = s_SQLStr01 & " WHERE"
s_SQLStr01 = s_SQLStr01 & " (小分類 Like ?)"

上記のSQLに、『「小々分類」の列にパラメータを使うよ 』というだけの設定を追加する。
「(小分類 Like ?)」を「(小々分類 Like ?)」に書き換え。

パラメータの具体的な設定。
「s_PrmNm1 = "Prm中分類"」を
「s_PrmNm1 = "Prm小分類"」に書き変え。(パラメータ名の設定)

「Set o_ParamRange1 = Worksheets("sheet1").Range("z1") 」を
「Set o_ParamRange1 = Worksheets("sheet2").Range("aj1") 」に。パラメータにしたいセル位置の指定。シート名を間違えないようにする。

「o_ParamRange1.Offset(0, 1).Value = "小分類"」を
「o_ParamRange1.Offset(0, 1).Value = "小々分類"」に。パラメータにしたいセルの右に、どの列をパラメータにしたかが分かりやすいように列名を入れる。

実行。

このコードは、1つのQueryTableオブジェクトに対して何回でも実行できるので、
もし、「Set o_ParamRange1 = Worksheets("sheet2").Range("z1") 」を書き間違えたら、
正しく修正して再度実行。

===================================

入力規則(データタブ→データの入力規則アイコン)で、ドロップダウンリストを作ります。

中分類のリスト内容は、
2つめのQueryTableオブジェクトにて、中分類で一番少ないリスト数のものを表示させたうえで、
2つめのQueryTableオブジェクトの「小々分類」の列を、
ドラッグで縦に、普通に範囲指定。
このとき、1行目の列名も含めて選択します。リストが1行だった場合、次回にリストが1行しか表示されなくなってしまうため。
(列名を選んでもエラーにならず、自段階のリストが空白になるだけなので心配はいりません)
リスト自体は「同じ値が自動的にグループ化されて」空白行も字度的に無くなり、ドロップダウンリストに表示されるようになります。

※同左を確認出来たら、再度、念のため、ここまでの状態を上書きして、ファイルを再起動。
パラメータが増えてもファイルを開く速度の遅さは変わらないことをチェック。

===================================

★注意!!!

自ファイルの内容を段階的に見ているせいか、一応、ファイル名やパスが変わるとダメっぽいです。

その場合、SQLを書く直すか、リスト自体を作り直す必要があるかもです。