★★★★★★Access2000VBA・Excel2000VBA独学~★★★★★★ 超重要!!!『 SQL の学習用 』 ★★★★★★~ ODBCでQueryTableオブジェクトを自動作成するサンプルコード)。多分、2000以降の全バージョンで使えると思います。~ついでに、セルの値で結果表示を自動で切り替える「パラメータクエリ」のVBAでの自動作成も。~
※まだ書きかけです。すみません。
※間違ってたらすみません。
※メモ書きなので、自分でも意味不明な箇所も多いです。ごめんなさい。
目次
★ はじめに
★ サンプルのダウンロード:サンプルのExcelファイルについて
★ サンプルのイミディエイトウィンドウでの「外部ファイルの全てのシート名の取得」について
★ ExcelでのSQL文の「方言」についての概要
★ SQLのことがまだよくわからない方が「SQLをのVBAコードをできるだけ素早く書く」ための方法
★ プログラムについてのその他の重要な説明
★ パラメータクエリのVBAでの自動作成方法
▼ 何もない状態からのパラメータクエリの作り方の大すじ
※パラメータ用のセルを作る場所について
▼ パラメータクエリができてからの操作について
★ パラメータクエリをVBAで自動作成するプログラム例
▼ 「すでに作成されたQueryTableオブジェクト」に対して、パラメータを作成する例3つ
(1個、2個、3個のパラメータの場合の例)
◎ パラメータが1つだけの場合
◎ パラメータが2つの場合
◎ パラメータが3つの場合
▼ そもそも「QueryTableオブジェクト自体」が作ってない場合のパラメータクエリの自動作成のプログラム例
◎ 1つめ:パラメータ呼び出し元プロシージャ(2010でテストして動きました。)
◎ 2つめ:呼び出されるプロシージャ(とりあえずこのサンプルプログラムでは、こちら側でパラメータを作ります。こっちらも2010で動きました。)
※Shift+TABキー、もしくは、Homeキー、Homeキー+TAB数回、を押すと、目次付近に戻れます。
※補足
「ODBC」とは、「ODBC接続」のことで、Microsoft Query の操作で使われる「データのソースに対する」、「データの接続方式」です。Microsoft Query の操作をマクロ記録すると、ODBCでの接続のコードが自動生成されます。
「データの接続方式」には、「ODBC」形式以外に、「OLEDB」形式もあります。
ADOやDAOなどを使う時は、「OLEDB」形式のほうが多いのではないかと思います。
「ODBC」では、OSの機能の「ODBCデータソース」という機能を使うと、テキストファイルなどもSQLを使って読むことができます。(単純な「テキストインポート」の機能ではSQLを使いながら吸い込むことができません。)
※本記事はあくまでも、読み込む先のシートが1シートにつき1つの表で、かつ、リスト形式=データベース形式の表=動的な表となっていることが前提です。
============
以下、本文です。
一応、SQLを学習できる小さなプログラムを作ってみました。
このプログラムは、「VBAが上達したい」「集計をもっと簡単にやりたい」という、「独立したばっかり」の、まだ「資金の少ない方」の目線、そういう方向けに一番に書きました。
でも、もちろん、チームや部署単位で効率化したい、プログラミングやSQL自体を学んで、「Excelと電卓の延長としてだけではなく、真のコンピュータ、真のデータ管理機能、として使いたい」という方向けでもあります。
そういう方々にも是非、読んで、実際に、SQLを試して持てほしいです。
PowerPivot(パワーピボット)、PowerQuery(パワークエリ)、リレーション機能、テーブル機能、といった、比較的新しい機能とかなり似たようなことができ、でも、自動化しやすくて扱いも簡単なケースも少なくないため、それらの新しい機能とともに、より、選択肢が増えると思います。
「ループがあれば大丈夫」「ループだけがあれば怖いものない」という「誤った考え方ばかりを強要されて教わってきてしまった方」にも是非!!!
逆に、コスパアップ目線・コスパアップ意識がもともと無い方や、「時間」を「もったいない」と思わない、くさるほど時間のある方、資金が有り余っている方は、基本、今すぐには読まなくても大丈夫です。
ただ、そういう方であっても、いつかは読んでいただき、「SQL」や「MicrosoftQuery」「QueryTableオブジェクト」の便利さを知っていただけたらな・・・、と思います。
なお、特に、プロのExcelVBA講師の方々は是非もっとSQLのことを広めてほしいなと思います。
子供たちの未来はあなたがたにかかっているのですから。
★ サンプルのダウンロード:サンプルのExcelファイルについて
バージョン2010で作り、動作は2000と2010で確認を行いました。
もちろん、「完全」ではなく「テキトーです。」
すべてのバージョンでチェックはしてないので、エラーが出たらご自分で治すか、分かる方に直してもらってください。
でも、SQLの学習やVBAの基本の学習などには、意外と便利に使えると思います。
※あくまでも、読み込む先のシートが1シートにつき1つの表で、かつ、リスト形式=データベース形式の表=動的な表となっていることが前提です。
以下の「サンプルのダウンロード」、のリンクからダウンロードできます。
ウィルスチェックはESETでやりました。
解凍するとxlsとxlsmが1個ずつ入っています。
「xls拡張子」のほうは2000~2003用
「xlsm拡張子」のほうは2007以降用
です。
あと、「5.xls」も入っています。
「5.xls」はデータの読み書きテスト用のブックです。
「Sheet1」のシートモジュールに書いてあるプログラムで「D:\1」フォルダを作成してから、その中に置いてテストしてみてください。
もちろん、好きなフォルダに入れてもOKですので、その際は、プログラムの中の読み込み先のパス(「s_TrgFNm001jj = "D:\1\5.xls"」)の部分を書き換えてください。
「xls拡張子」と「xlsm拡張子」は、
両方とも、10枚のシートがあらかじめ作ってあり、各シートのオブジェクト名(=CodeNameプロパティで取得できる名前)を、「Sheet01」「Sheet02」「Sheet03」・・・・のように、前ゼロを付けたオブジェクト名に変えてありますのでそこだけ要注意です。(プロジェクトウィンドウ内でのシートの並び順の関係で前ゼロを付けました。)
特に、『 ご自分でプログラムを一部修正したり・機能追加等々をするとき・かつ・CodeNameプロパティを使いたいとき 』、「だけ」は、注意してください。
ただ、一般的な「Worksheets("シート名")という使い方自体は、通常通りにおこなえます。
また、以降でお示しするプログラムがすべてのシートモジュールと標準モジュールに、修正すべきところは修正して、セットしてあります。
ですので、すぐに・・・、
・「VBA+ODBC+QueryTableオブジェクト」での、
・「SQLを使った複雑な条件での絞込や集計・リレーション」も「同時にやりながら」の、
・「閉じた外部ファイルからのシートデータの吸い込み」、
・・・が試せます。
なお、「xls拡張子(2000~2003用)」、「xlsm拡張子(2007以降用)」、両者ともに、プログラム内容は「まったく同じ」です。
それぞれにとっての「独自」のコードは、一切、在りません。
そして、パワークエリ(Power Query)、
パワーピボット(Power Pivot)、
リレーションシップ機能、などの新しい・かつ・似たことができる機能たち、
「よりも」、
・「便利・手軽」で、かつ、
・「高速」で、かつ、
・「汎用的」傾向にあり、「今の知識をそのまま利用できる人も少なくなく」、かつ、
・「VBAとも相性良く簡単にリレーションなどを自動化でき、」、かつ、
・表が「テーブル機能」でテーブル化されていなくてもリレーション可能、かつ、
・何枚の表でも、5枚でも6枚でも、簡単にドラッグ一発、あるいは、十数文字の記述でリレーション可能、かつ、
・テキストファイルなども簡単に扱え、
・ぶっちゃけ集計やリストアップの自動化をしたいなら、新しい機能たちよりも便利、
・・・・ですので、そういった「パワークエリ」等々の新しい機能たちとの違いを理解し、お互いが活かせる場面を探すのにも是非、使ってほしいと思います。
★ サンプルのイミディエイトウィンドウでの「外部ファイルの全てのシート名の取得」について
※こちらも、あくまでも、読み込む先のシートが1シートにつき1つの表で、かつ、リスト形式=データベース形式の表=動的な表となっていることが前提です。
サンプルファイルでは、「外部ファイルの全てのシート名の取得(=調査)」ができます。
調べ方は、イミディエイトウィンドウにて
? sn("Excelファイルのフルパス")
と入力してEnterします。
例えば「D:\1\5.xlsx」というファイルの場合、
? sn("D:\1\5.xlsx")
と入力してEnterします。(この「sn」は、「SheetName」の略としました。)
すると、そのままイミディエイトウィンドウの次の行から、そのExcelファイルのすべてのシートの名前(名前定義?の名前も含む)を列挙してくれます。
同様に、(ダウンロードできるサンプルファイルにはまだsn2プロシージャを追加してないので)、sn2のプロシージャ内容を標準モジュールに追加したのちに、
? sn2("D:\1\5.xlsx")
(「2」が増えただけ)
とやると、テーブル名とともに、列名もイミディエイトウィンドウに一覧表示されます。
SQLを書くときなどに参考として使えます。
xlsm、xlsx、xls、が調査の対象となります。
ただ、列名まではわかりませんので、列名は、『 SELECT * FROM [シート名$] 』というSQL文でいったんテーブルを吸い込んで、その結果の表の列名を見て、そんな形で調べてみてください。
※2021/02/04 追記
サンプルでもブック内の全てのシートの、「列名」もわかるようにしました。
サンプル内に、「sn2」というプログラムを追加しました。
「? sn2("調査対象のブックのフルパス")」というかたちでイミディエイトで
調べてみて下さい。
ついでに、INSERT や UPDATE でエラーになってたので、それもエラーに
ならないようにしておきました。
※補足
Excelの場合は、シート名(=テーブル名)はバッククォートで囲んでもいいし角カッコで囲んでもどちらでもOKです。ただし、「$」は必ずつけます。ODBCデータソースなどを使って、テキストファイルをSQLを使って吸い込みたいような場合は、テーブル名に「$」は要りません。
例
ワークシート全体:Select * from [Sheet1$]
名前なしセル範囲:Select * from [Sheet1$A2:E10]
名前付きセル範囲:Select * from 範囲名
( ↑「範囲名」というのは「名前の定義」機能で付けた名前のことです。)
「SQL文」という命令文は、「Microsoft Query」の画面や、「VBA」の画面で書くことができます。
MicrosoftQueryの画面のSQL画面(=SQLダイアログ=SQLビュー)では、「SQL文」という命令文を書くときには、縦に、句ごとや列名ごと、演算子?ごと(論理演算子や集合演算子など)、等々で、改行しても動きます。
命令文だからと言って、横にぶわーっとつなげて書かなくてもいいのです。
例えば、「( 」だけ、とか「 )」だけ、とか、「カッコ1個だけで1行使ってもダイジョブ」です。ただし、空白行は入れてはいけません。
一方、Microsoft Queryの画面以外では、VBAプログラムで「SQL文」という命令文を書けます。
どちらかというとこちらで書くことのほうが多いかもしれませんが、こちらで書くときには、変数を使って、縦に書いて、「&」でつなげていくとわかりやすいと思います。
例えば以下のように。
変数 = ""
変数 = 変数 & "SELECT "
変数 = 変数 & " 列名01"
変数 = 変数 & " ,列名02"
変数 = 変数 & " ,列名03"
変数 = 変数 & " ,列名04"
変数 = 変数 & " FROM"
変数 = 変数 & " テーブル名A INNER JOIN テーブル名B"
変数 = 変数 & " ON テーブル名A.列名 = テーブル名B.列名"
変数 = 変数 & " WHERE"
変数 = 変数 & " テーブル名A.列名 = '条件値';"
(※ExcelでのSQLの場合では、多くの場合は、「テーブル名」は「シート名に$記号を付けたモノ」になります。またテーブル名は角カッコ・または・バッククォートで囲む必要があります。)
(※上記のSQL文はHTMLのせいで表示に全角スペースを使ってしまってますので、「コピペ利用」「しないで」下さい。SQLでは命令語句や列名などの区切りに全角スペースを使うとエラーになりますので。)
このとき、句と句、演算子と演算子、列名と列名、などの間には、「半角でなら」「スペースをどんだけ入れてもOK!」です。
「全角のスペースはエラーになるのは」普通 通りです。
MicrosoftQueryの画面の「SQLダイアログ(SQLビュー)」では、上記の、変数や & 、""、などを取っ払った感じで、縦に改行して命令できます。
Excelの場合は、シート名(=テーブル名)はバッククォートで囲んでもいいし角カッコで囲んでもどちらでもOKです。ただ、いずれかで囲まないと基本、エラーになります。
特にFROM句は絶対にそれらでの囲みが要りますが、他の句では要らない場合もあるようです。ご自分でも試してみてください。(このへん、ちょっとわかりません。僕のPCが、現在、2010と2019が共存なのでそれでおかしくなっているのかもしれません。)
なお、Excelシートの場合は、テーブル名には「$」が必ず必要です。
これも、つけないとエラーになります。
また、AccessからExcelシートをSQLで参照する時も、「$」は必要だったように思います。
ODBCデータソースなどを使って、テキストファイルをSQLを使って吸い込みたいような場合は、テーブル名に「$」は要りません。
あと、VBAの場合、「変数 = 変数 & "××××××××××××××"」みたいな形態で書くことが多いです。
一応、「半角スペース+_ (アンダーバー)」で改行して書くこともできますが、その書き方の場合に限っては文字数に(数百文字までという)限界があってどこかでエラーになるに決まってて面倒くさいですし、そもそも、文が完成するまでいちいちエラーになるのでさらに面倒くさいため、僕は「変数 = 変数 & "××××××××××××××"」を使います。
短い命令文を書くなら「半角スペース+_ (アンダーバー)」で改行してもいいんですが、もう変数を毎行で書くほうがいろいろ付けたしや修正もしやすいし、それでやっています。
でも、基本自由なので、お好きな方で。。。
SELECT句などのFROM句以外では、「テーブル名.列名」のように「テーブル名をつける」、ということが要らず、「列名」だけを書いてもOKな場合も多いです。特に1つのテーブルしか扱っていないときなどは要りませんので、そういうのは普通と同じです。
なお、「テーブル名.列名」のように書くときは、テーブル名にはもちろん「$」が必要です。バッククォートや角カッコは要らない場合もあるかもしれません。うろ覚えですみません。また、できる場合とできない場合があります。
それから、「Microsoft Queryの画面・限定」ですが、自動生成されたSQL文をどこかにテキストファイルにバックアップしておいて、別のMicrosoft Queryの画面を表示した時に、(テーブルがまったく同じなら)そのとっておいたSQL文をSQLビューにコピペすると、クエリデザインの画面が再現されます。つまり、ドラッグや条件値の入力をまたやり直さなくてもいいのです。
これは、Accessの「クエリ」でもまったく同じことができます。
Microsoft QueryでのSQL操作では、次回開いた時にSQLがリセットされて消えてしまうこともあるのですが、そのとき、逐一、いちいち、SQL文をテキストファイルにバックアップしておくと、それを書き戻しさえすれば、クエリデザイングリッドの元々の状態が、「再現が一瞬で終わる」ので、かなりラクちんです。
VBAでSQL命令を書くときは、シートのモジュールに(コメントアウトして)メモしておいてもいいと思います。変数丸ごと。
ExcelでのSQLの場合、その「テーブル名」には「Sheet1!A1:F10」みたいな範囲指定や、「名前定義の名前」なども使えたかと思います。(うろ覚えです。すみません。)→と思ったらWebにありました!→『 Excelファイルに接続(ADO) 』
以下、引用。
ワークシート全体:Select * from [Sheet1$]
名前なしセル範囲:Select * from [Sheet1$A2:E10]
名前付きセル範囲:Select * from 範囲名
(↑3つ目の「範囲名」というのが「名前の定義」機能で付けた名前のことです)
ワイルドカードは % や _ などで、一般的なようです。(Accessは特殊で * や ? を使います。)
ASでの別名は使えます。(列名、テーブル名、ともに)
ASを使った結果、シート上に結果表示がなされたときに、その列名にシングルコーテーションが付加されてしまう場合は、ASの列名か、その内容の数式等々かいずれかを角カッコで囲むと正常にシングルコーテーション無しで表示された気がします(うろおぼえですみません。)
副問い合わせ(サブクエリ)も使えます。
「Case文」は使えないので、「Switch関数」?で代用する必要があります。
(これは、AccessのMDBでのSQLと同じです。)
SQL内でもVBAのInteractionオブジェクトのメンバの関数の一部は、「SQL文の中で直接」使えるもようです。「Switch関数」「IIF関数」「Choose関数」などです。
が、もちろん、SQL文の外で普通のVBA関数や変数を使って、SQL文に「&」を使って、混ぜて、結合してSQL文を作成していくことも可能です。
それから、Excelの場合、すごく不思議なんですが、SQL文の最後につける「;(セミコロン)」はExcelの場合はなぜか不要です。もちろんつけてもいいです。
ただ、あえて付けたほうがいい場合とあえて付けないほうがいい場合(特に、1つのSQLで、VBA側だけでなくMicrosoftQueryの画面での操作も可能にしたい場合など)があります。2007以降のMicrosoftQuery(結果がListObjectに埋め込まれたQueryTableオブジェクトになるケース)だけかもしれませんが・・・。
関連記事はこちら→『 ★★★Access2000VBA・Excel2000VBA独学~「QueryTableオブジェクト」~~「VBAプログラム」からも、「MicrosoftQueryの画面」からも操作が可能となる、そのための「VBAからのSQLの書き方」や「前提条件」など(概要説明のみ)~ 』
★ SQLのことがまだよくわからない方が「SQLをのVBAコードをできるだけ素早く書く」ための方法
MicrosoftQueryの画面の「SQLビュー」には、横にぶわーっとつながったSQL文が自動生成されます。(Accessの「クエリ」も同じです。)
ドラッグでリレーションしたり、条件入力をして完了すると、その作業がずべてSQL命令に自動変換されて、SQLビューに表示できるようになります。
SQLのことがまだよくわからないうちは、このSQLビューに自動生成されたSQL文を活用します。
というのも・・・、Microsoft Queryで自動生成されたSQLをそのままVBAプログラムにペッタンコして流用すると、「あまり意味がわからなくてもSQL命令文が実行できてしまう」からです。
もちろん、いずれは、というか、少しずつ、自力でSQL文がかけるようになることが必要ですが、でも、はじめのうちは(特に独学の場合は)先生もおらずやはり不安です。
そのような中では、慣れるまで、「Microsoft Query」がある意味「先生」になってくれますので、自動生成されたSQL文をどういう意味なのかを探りつつ、そのまえに、まずはプログラムとして動くようにしてしまいます。
やり方としては以降のような感じです。
まず、Microsoft Queryで自動生成されたSQL文を、句ごとや演算子ごと(論理演算子や集合演算子など)、列名ごとなどで改行します。
それは、TeraPadやメモ帳などのテキストエディタで「置換」メニューによって、1~3回の操作で完了させます。Wordでもできます。手作業で1行ずつ改行しなくても一瞬で改行が終わるのでラクちんです。(僕はいつもTeraPadを使っています。)
MicrosoftQueryのSQLビューのSQL文は、Accessのクエリの場合と同じで、あまり切れ目がないのでぱっと見、文字だらけでわけがわからないと思いますが、TeraPadなどのテキストエディタやWordなどで・・・、
・「, 」(=カンマと半角スペース)を
「半角スペース+カンマ+半角スペース+改行コード」に置換、とか、
・「AND 」(=ANDと半角スペース)を
「半角スペース+AND+半角スペース+改行コード」に置換とか、
そういった処理をすると、縦方向にすこし見やすくなるのです。
(あえて半角スペースを前につけて置換するのは、SQLとしてのエラーが出ないようにするためです。いつか意味がわかると思います。)
たとえば以下のような横につながったSQL文があったとします。
SELECT 列名01 ,列名02 ,列名03 ,列名04 ,列名05
FROM テーブル名A INNER JOIN テーブル名B ON テーブル名A.列名 = テーブル名B.列名
WHERE テーブル名A.列名 = '条件値';
(※ExcelでのSQLの場合では、多くの場合は、「テーブル名」は「シート名に$記号を付けたモノ」になります。またテーブル名は角カッコ・または・バッククォートで囲む必要があります。)
これは短い例なので、文字列が右端までいっていませんが、通常は「切れ目のない文字の海」が何行も延々と続く・・・というイメージになります。
で、まず最初に、それをTeraPadやメモ帳などの「置換」機能を使って、一発変換を(条件を変えつつ)、2、3回繰り返し、以下のような状態にします。
SELECT 列名01
,列名02
,列名03
,列名04
,列名05
FROM テーブル名A INNER JOIN テーブル名B
ON テーブル名A.列名 = テーブル名B.列名
WHERE テーブル名A.列名 = '条件値';
(※ExcelでのSQLの場合では、多くの場合は、「テーブル名」は「シート名に$記号を付けたモノ」になります。またテーブル名は角カッコ・または・バッククォートで囲む必要があります。)
で、これをもう少し整形して以下のような感じにします。
SELECT
列名01
,列名02
,列名03
,列名04
,列名05
FROM
テーブル名A INNER JOIN テーブル名B
ON テーブル名A.列名 = テーブル名B.列名
WHERE
テーブル名A.列名 = '条件値';
(※ExcelでのSQLの場合では、多くの場合は、「テーブル名」は「シート名に$記号を付けたモノ」になります。またテーブル名は角カッコ・または・バッククォートで囲む必要があります。)
で、最終的には、これに変数部分をくっつけて・・・
変数 = 変数 & "SELECT "
変数 = 変数 & " 列名01"
変数 = 変数 & " ,列名02"
変数 = 変数 & " ,列名03"
変数 = 変数 & " ,列名04"
変数 = 変数 & " FROM"
変数 = 変数 & " テーブル名A INNER JOIN テーブル名B"
変数 = 変数 & " ON テーブル名A.列名 = テーブル名B.列名"
変数 = 変数 & " WHERE"
変数 = 変数 & " テーブル名A.列名 = '条件値';"
(※ExcelでのSQLの場合では、多くの場合は、「テーブル名」は「シート名に$記号を付けたモノ」になります。またテーブル名は角カッコ・または・バッククォートで囲む必要があります。)
・・・という感じになるように、
「"」と「" 」のあいだに、1行ずつコピぺしていけばOKです。(スペースも。)
自動的に「変数 = 変数 & " 」や 終わりの「"」をくっつけるプログラムを作れば一瞬で終わります。
(※上記のSQL文はHTMLのせいで表示に全角スペースを使ってしまってますので、「コピペ利用」「しないで」下さい。SQLでは命令語句や列名などの区切りに全角スペースを使うとエラーになりますので。)
このとき、
「SELECT」で列を特定し、
「WHERE」で行を特定しています。
「FROM」は「データを取り出す表」の、その「範囲」です。
もう少し普通の言い方をすると、
「FROM」に書かれた表の範囲から、
「SELECT」で列を特定し、
「WHERE」で行を特定して「仮想表」を生成します。
複数行 × 複数列、なら、「表範囲」が特定されるイメージで、
1行 × 1列、なら「1つのセル」が特定されるイメージ・・・、
という感じです。
基本、「FROM」のところでは、「1つの表」だけではなく、
「複数の表」を範囲として指定することもできます。
その際、「VLOOKUP関数での表と表の紐つけ」のような「リレーション(リレーションシップ」という作業も行えます。(バージョン2016などで使える「リレーションシップ機能」と同じ機能です。商用利用としてはExcel以外の製品において30年前からある機能で、Excelにはバージョン2000の前、97でも使えてました。もっと前から使えていたかもしれません。)
なお、「FROM」のところでは、2つの表だけでなく、5つでも6つでも、複数の表を簡単にリレーション(=横結合)することができます。
以上は、SQLの意味がさほどわからなくても、できます。
単純に・・・・、
「変数 = 変数 & "××××××××××" 」の、「 " 」と「 " 」のあいだ(=つまり、「××××××××××」のところ)に、1行ずつコピペしてしまえばいいのです。
(このとき、SQL文を何も触らないように気を付けます。
句と列名やテーブル名の間のスペースがなくなるとエラーになってしまうので。)
なお、SQL文内でWHERE条件などの中で「文字列」の意味を表す場合は、「"」ではなくて「'」を使います。
(=ダブルクォーテーションではなくて、シングルクォーテーションを使います。)
なので、「"」(ダブルのほう)を複数個、連ねて記述する必要はありません。
あと、ExcelのSQLの場合は、「ワイルドカード(置き換え文字)」は「*」ではなく「%」になります。(=アスタリスクではなくパーセント記号です。)
これはAccessの場合と異なりますが、「%」のほうが一般的で、Accessのほうが特殊です。
そういった意味で、MicrosoftQuery は、SQLの勉強のお供になります。
※ちなみにですが、MicrosoftQueryのSQLビューでも、半角スペースはどんだけ使ってもOKです。
なので、以下のようにテキストファイルで書いておいて、それをSQLビューにコピペしても、SQLは実行できます。(もちろん、スペースは全部半角です。先頭に必ず半角スーペースを入れておけばエラーになることもありません。
SELECT
列名01
,列名02
FROM
テーブル名A INNER JOIN テーブル名B
ON テーブル名A.列名 = テーブル名B.列名
WHERE
テーブル名A.列名 = '条件値';
(※ExcelでのSQLの場合では、多くの場合は、「テーブル名」は「シート名に$記号を付けたモノ」になります。またテーブル名は角カッコ・または・バッククォートで囲む必要があります。)
これはAccessのクエリのSQLビューでも同じです。
(※上記のSQL文はHTMLのせいで表示に全角スペースを使ってしまってますので、「コピペ利用」「しないで」下さい。SQLでは命令語句や列名などの区切りに全角スペースを使うとエラーになりますので。)
ちなみにですが、上記のSQLの、
「 テーブル名A INNER JOIN テーブル名B
ON テーブル名A.列名 = テーブル名B.列名 」
という部分の意味は、
・テーブル名Aとテーブル名Bを、
・テーブル名Aの側の「列名」の列と、
・テーブル名Bの側の「列名」の列とで、
・INNER JOIN(=「内部結合」)する、
という意味です。
「内部結合」とは、
「AとB、両方の ” 列 ” に存在する値を含む ” 行 ” だけ、を、お互いに横に結合する」・・・、
というイメージです。
ちょうど、Vlookup関数で行うような2つの表の紐付けと同じようなことですが、ただ、VLookup関数のように、「紐付けした列の右側しか参照できない」などの制限はありません。
紐付けした列の右でも左でも、参照、あるいは表示させることができます。
サンプルなので動かなかったらごめんなさい。
すでにシート上にQueryTableオブジェクトがある場合は、
(a)QueryTableオブジェクトのSQL内容だけを更新する方法と、
(b)あってもなくてもいったんそのQueryTableオブジェクトを削除してから新設する方法
の2つが考えられると思いますが、とりあえず後者を選びました。
理由は、大きくは2つあります。
1つ目は、QueryTableオブジェクトを作成した自ファイルをも「覗きに行きたい」・・・、つまり、「自ファイル1つで完結したい」、、、、、、「自ファイル1つで」多段的にSQL文で条件絞り込みや条件付き集計をしたい・・・・というときがあります。
それは、「かなり複雑な条件」のときに解決策のひとつとして、とても助けになります。
(複雑なループのプログラムを書かなくて済む!!!!!!!!!!!からです。)
で、その場合、自ファイルの格納場所が変わってしまうと、「ソースのファイルが見つかりせん。」といった旨のエラーになることがあります。
それをできるだけ回避したいので、いったん削除して新設するほうを選んでしまいました。
QueryTableオブジェクトの内容更新だけでも可能かもしれませんが、何か面倒くさいことがあるといけないので、とりあえず、いったん削除して新設するほうを、「とりあえず」選んでしまいました。(もし必要なら、そういうSQLの内容変更と更新をするだけのプログラムの方が、多分考えることが少なくて簡単な気がしますので、ご自分でも作ることにチャレンジしてみてください。)
2つ目は、QueryTableオブジェクトを生成すると、名前の定義にもそれに紐ついた定義設定が勝手に追加されるのですが、そちらもある程度、QueryTableオブジェクトの内容によって連動して名前が書き換わったほうがいいかなと思い、とりあえずそうしました。
もちろん、名前の定義自体を単独で操作できるなら(a)の方法でもOKだと思いますが、下手にいじるとQueryTableオブジェクトが壊れそうな雰囲気だったので、知識不足でとりあえずやめました。
名前の定義の名前が、セル範囲はそのままに名前だけリネームできればもしかしたらいいのかもしれませんが・・・。ちょっと調査不足でよくわかりません。
※とりあえず、QueryTableオブジェクトを消してないのに、同名の名前定義を消すと、そのQueryTableオブジェクトは機能しなくなります。名前定義の名前を変えても同じ現象が起こるかもしれません。未確認ですのでご自分でも試してみてください。
また、どのソースにも対応する汎用的なQueryTableオブジェクトを作るときは、(名前の定義の名前なんてどうでもいいので)そういうことを考えることは不要かもしれませんが、このサンプルでは、とりあえず、考えてしまいました。
あと、QueryTableオブジェクトが作成されている時、そのSQL内容だけを変えて、「更新」することも可能です。ただ、その場合、QueryTableオブジェクトの名前と名前定義の名前も、その内容にみあったものに変えないと、「1つのファイル=自ファイルの中で」、多段的に・ネスト/入れ子的にSQLをかけていくときに戸惑うことがあるので、それも一応見越して、このサンプルでは、とりあえず、(b)の「QueryTableオブジェクトを削除してから新設する方法」をとってしまいました。
・・・というわけで、、人によっては色々と作り変えなどが必要かとは思います。
また、完全に作りこんでいるわけではないので、どんなバグが潜んでいるかはわかりません。
エラーが出たらご自分でご解決ください。
あるいは、分かる方に解決してもらってください。
自ファイルを覗きにいって、自ファイルのデータに対してQueryTableを作った場合、
で、かつ、
『 生成した「QueryTableオブジェクト」の結果表にて「Microsoft Queryの画面」を使いたい 』
という場合は、1つめのQueryTableの場合は大丈夫です。
それができます。
右クリックメニューの「クエリの編集」より、「Microsoft Queryの画面」を使ってSQL文の内容を再編集できます。
しかし、2つめのQueryTableオブジェクト以降は、生成されたQueryTableから『 右クリック操作にて「Microsoft Queryの画面」を使おうとした場合 』、「認識できません」的なエラーとなり、起動できませんでした。(もしかしたら、これも、僕のPCは2010と2019を混在させてるのが原因でエラーになるのかもしれません。ご自分のPCでも試してみてください。)
これは基本的には、2010でも、2000でも同じっぽいです。(でも、ほぼ未検証)
(※OSがWin2000やWin98で、Excelが2000の組み合わせだと、これは起こりません。いくらでも多段階に自ファイルを覗けます。XPだとSP3になると多分ダメです。SP2までは良かった気がします。ただ、いずれも自ファイルをMicrosoftQueryで覗くときは動作が遅いですが・・・。VBAだけなら高速です。)
なので、XP+Excel2000以降で、QueryTableオブジェクトにおいて、自ファイルを読みに行ったり、多段階なものを作りたいときは・・・・、
・VBA+ODBCや、
・VBA+OLEDB
・・・・などでQueryTableオブジェクトを作るしか方法がなさそうです。(いずれもSQLを使えます。)
でも、そのとき、まだ不慣れな方の場合、SQLを生成するのに、MicrosoftQueryは役立つと思います。
1段階だけなら自ファイルでもエラー無くMicrosoftQueryの画面が使えるようですので。
(バージョン違いのExcelを複数インストールしてあると、それも使えないかもしれませんが・・・)
SQLがExcelで使えると、「複雑な条件での集計やリストアップ」に限っては、(ループしなくていいので)「無駄なワークシート関数や無駄なVBAプログラム」がかなり減ると思いますので、是非、この機会に、SQLやQueryTableオブジェクトの操作に興味をもってみてください。
では以下、サンプルプログラムです。
(01) 各シートモジュールにコピペするコード
「test01」というプロシージャにて、SQLを使って外部のデータ(シート)を読み込めます。
SQLを使うので、もちろん、『 複数のシートをリレーションさせて集計やグループ化等々をしたもの 』を吸い込めます。
吸い込んだ際には、自動的に、名前の定義に、QueryTableオブジェクトと同じ名前の名前定義(Nameオブジェクト)が新設されます。
「QTDell01」というプロシージャでは、その読み込んだデータ(QueryTableオブジェクト)を削除します。2010でのテストでは、もともと「QueryTableオブジェクト」を削除すると連動して名前定義も消えますが、2000などでは残ってしまうのでそれを強制的に削除するようにしています。
なお、QueryTableオブジェクトを手動で削除する場合は、事前に表を右クリックして、「データ範囲プロパティ」にて「名前」を調べます。その後、列丸ごととか、行丸ごとを削除します。そして同じ名前の名前の定義も削除します。
でないと、名前の定義での名前が増えすぎて、自ファイルをネスト的・入れ子的にSQLをかけるときに難しくなってしまいますのでご注意ください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
' ' Option Explicit '############################################################################### 'このシート専用のQueryTableオブジェクトの削除(名前の定義も一緒に消えます。) '############################################################################### Sub QTDell01() Call QTDelFunc01(Worksheets("Sheet1")) End Sub '############################################################################### 'QueryTableオブジェクトを自動作成するプログラムの一例 '他のExcelファイルや自ファイルからの、SQLを使ってのデータの吸い込み '############################################################################### Sub test01() Dim s_TrgFNm001jj As String '外部の、吸い込みたい先のファイル Dim s_TrgFoldPath001jj As String 'そのファイルが在るフォルダ Dim s_SqlStr01jj As String '吸い込むときのSQL内容 Dim s_ChkQTobjNm01jj As String '付けたい、「QueryTableオブジェクトの名前」 Dim o_ImpSht001jj As Worksheet '今のファイルの中の、QTオブジェクトを生成したいシート(オブジェクト) Dim s_ImpCelAddr001jj As String 'そのシートのQTオブジェクトを生成したいセル位置 '★ 設定部 '他ファイルデータの吸込み用設定 s_TrgFNm001jj = "D:\1\5.xls" '外部の、吸い込みたい先のファイル s_TrgFoldPath001jj = "D:\1" 'そのファイルが在るフォルダ Set o_ImpSht001jj = Worksheets("Sheet1") '今のファイルの中の、QTオブジェクトを生成したいシート(オブジェクト) s_ImpCelAddr001jj = "$A$1" 'そのシートのQTオブジェクトを生成したいセル位置 ' '自ファイルデータの吸込み用設定 ' s_TrgFNm001jj = ThisWorkbook.FullName '外部の、吸い込みたい先のファイル ' s_TrgFoldPath001jj = ThisWorkbook.Path 'そのファイルが在るフォルダ ' Set o_ImpSht001jj = Worksheets("Sheet1") '今のファイルの中の、QTオブジェクトを生成したいシート(オブジェクト) ' s_ImpCelAddr001jj = "$A$1" 'そのシートのQTオブジェクトを生成したいセル位置 o_ImpSht001jj.Activate o_ImpSht001jj.Range("A1").Select s_ChkQTobjNm01jj = "QTSht01_Imp_" '「重複を調べたい=付けたい」 '「QueryTableオブジェクトの名前」の設定 'SQL文の設定 s_SqlStr01jj = "SELECT * FROM `Sheet1$`" ' s_SqlStr01jj = "INSERT INTO `Sheet1$` (具) VALUES ('ラム')" ' s_SqlStr01jj = "UPDATE `Sheet1$` SET 具 = 'ラム肉' WHERE 具 = 'ラム'" '※↑テーブル名は上記のように「`」(バッククォート)で囲むのもOKですし、 ' 「角カッコ」で囲むのもOKです。 ' 角カッコで囲むと『 [Sheet1$] 』となります。 ' フィールド名に別名を付けたときは、別名に角カッコを使うほうが ' 結果の表のフィールド名に「’」が付かないので便利かもしれません。 '★ チェック部 '指定したブック内に、指定した名前を含むQueryTableオブジェクトが '既に存在していないかどうかをチェック。 '在ったら中断。 If QTSonzaiChk01(ThisWorkbook, s_ChkQTobjNm01jj) = 1 Then Exit Sub Else End If '★ 実動部 'SQLの実行=SQLでの吸込み Call MSQryOnlMakeByODBCFunc001(s_TrgFNm001jj, _ s_TrgFoldPath001jj, _ s_SqlStr01jj, _ s_ChkQTobjNm01jj, _ o_ImpSht001jj, _ s_ImpCelAddr001jj) ' 呼び出し方法 ' Call MSQryOnlMakeByODBCFunc001("読みに行きたいファイルのフルパス", ' "そのファイルの在るフォルダのパス", ' SQL文, ' 結果表(QueryTableオブジェクト)につけたい名前, ' 結果を出力したい「オブジェクトとしての」シート. ' 結果表を出力するセルのアドレス(表の一番左上隅のセルの。) ' End Sub ' ' |
【おおざっぱな使い方】
▼ 00:上記コードを、すべてのシートのシートモジュールにコピペします。
(ダウンロードしたサンプルファイルは、10枚のシートがあらかじめ作ってあり、この処理がしてあります。※ただ、Sheet1のオブジェクト名を「Sheet01」のように、前ゼロを付けたオブジェクト名にに変えてありますのでそこだけ要注意です。)
01:結果表示したいシートのシートモジュールを開きます。
例えばSheet1のモジュールを開きます。
※サンプルだと「Sheet01(Sheet1)」というモジュールです。
▼ 02:外部ファイルを覗きにいきたいときは、test01() のプログラムにて、「★設定部」のところで、「'他ファイルデータの吸込み用設定」のところの4行分を書き換えます。
自ファイルのシートを覗きにいきたいときは、前述の部分・4行分をコメントアウトし、「'自ファイルデータの吸込み用設定」の4行のほうをコメントアウトをはずします。
どのように書き換えたらいいかは、コメントや今書かれている内容などを見ればすぐにわかると思います。
▼ 03:「s_ChkQTobjNm01jj = "QTSht01_Imp_"」の行で、吸い込み結果の表(QueryTableオブジェクト)につけたい名前を設定します。「Sht01」の部分を、今開いているシートモジュールにひもついたシートがわかるような名前、あるいは、「Imp」以降をSQL内容が自分である程度思い起こせそうな短い内容で、それを名前に変えるといいと思います。
▼ 04:イミディエイトウィンドウにて、覗きに行きたいファイルのシート名や列名を調べます。
(やりかたは『 ★ サンプルのイミディエイトウィンドウでの「外部ファイルの全てのシート名の取得」について 』にて前述してあります。)
シート名だけ調べたいときは、
? sn("調べたいファイルの絶対パス")、
列名も調べたいときは
? sn2("調べたいファイルの絶対パス")、 ※「sn」に「2」を付けただけです
で調べられます。
※なお、数十万件もあるExcelファイルを覗きにいく(調べに行く)ときは、結果が出るまで十数秒か数十秒、あるいは数分、かかります。
▼ 05:最後に、「s_SqlStr01jj = "SELECT * FROM `Sheet1$`"」の行を書きかえます。
一番簡単なのは、「Sheet1$」の部分(バッククォート残す)を、前項の04:で調べたテーブル名(=シート名)にしてみます。
▼ 06:普通にF5キーなどでVBA(test01)を実行します。
※SQL内容は色々と試し、コメントアウトなどでモジュール内にメモして残しておきます。
'★設定部
'他ファイルデータの吸込み用設定
s_TrgFNm001jj = "D:\1\5.xls" '外部の、吸い込みたい先のファイル
s_TrgFoldPath001jj = "D:\1" 'そのファイルが在るフォルダ
Set o_ImpSht001jj = Worksheets("Sheet1") '今のファイルの中の、QTオブジェクトを生成したいシート(オブジェクト)
s_ImpCelAddr001jj = "$A$1" 'そのシートのQTオブジェクトを生成したいセル位置
' '自ファイルデータの吸込み用設定
' s_TrgFNm001jj = ThisWorkbook.FullName '外部の、吸い込みたい先のファイル
' s_TrgFoldPath001jj = ThisWorkbook.Path 'そのファイルが在るフォルダ
' Set o_ImpSht001jj = Worksheets("Sheet1") '今のファイルの中の、QTオブジェクトを生成したいシート(オブジェクト)
' s_ImpCelAddr001jj = "$A$1"
(02)標準モジュールにコピペするコード
コピペだけします。
「部品」としてのプログラムなので特に何もしません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 |
' ' Option Explicit '############################################################################### 'QueryTableオブジェクトの削除(名前の定義も一緒に消えます。) '############################################################################### Function QTDelFunc01(o_WSjj As Worksheet) Dim o_KizonTeigiNm01 As Name If 1 <= o_WSjj.QueryTables.Count Then o_WSjj.Activate o_WSjj.QueryTables(1).Delete o_WSjj.Rows.Delete '↑ただの「Cells.ClearContents」だけだと '何かが残るみたいで自ファイル参照すると 'F1、F2、F3・・・みたいになってしまうことがあるので '一応、Rows.Deleteにした。でもCells.Deleteのほうがいいのかも? o_WSjj.Range("A1").Select Else End If 'xlsファイル用の名前の定義の削除処理。 'xlsの場合、QueryTableオブジェクトを削除しても '名前の定義が残ってしまうため。 ' o_WSjj.Names(o_WSjj.QueryTables(1).Name).Delete For Each o_KizonTeigiNm01 In o_WSjj.Names If 0 < InStr(1, o_KizonTeigiNm01, "", vbBinaryCompare) Then o_KizonTeigiNm01.Delete Else End If Next 'アクティブウィンドウの調整 ActiveWindow.Zoom = 100 'ズーム 100% ActiveWindow.FreezePanes = False 'ウィンドウ枠の解除 End Function '############################################################################### '指定されたブック内に、指定された名前を含むQueryTableオブジェクトが '存在するかどうかをチェックしたときに、ヒットしたらメッセージを出すだけの、 '(一応状態も数字で返す)関数。 '############################################################################### Function QTSonzaiChk01(o_WB02jj As Workbook, s_ChkQTobjNm02jj As String) As Integer Dim v_Answ01jj As Variant '★ 実動部 '同じ名前か、ほとんど同じ名前(接尾語があるだけの)の、 'QueryTableオブジェクトが存在するかチェックして '在れば中断する分岐。 'ちなみに、QueryTableオブジェクトが作成されると、 '名前定義にも勝手に設定が追加されるが、 'QueryTableオブジェクトをDeleteメソッドで削除すると、その設定も一緒に消えます。 'ただ、手動でシート上から手作業でQueryTableオブジェクトを削除すると '名前定義の設定は残ったままになってしまいます。 v_Answ01jj = KizonQTCheck01(o_WB02jj, s_ChkQTobjNm02jj) If v_Answ01jj(0) = "OK" Then QTSonzaiChk01 = 0 ElseIf v_Answ01jj(0) = s_ChkQTobjNm02jj Then MsgBox "「" & v_Answ01jj(0) & "」を含むQueryTableオブジェクト(=名前)が、" & _ vbCrLf & "「" & v_Answ01jj(1) & "」として" & _ vbCrLf & "「" & v_Answ01jj(2) & "」に見つかりましたので中断します。" & _ vbCrLf & _ vbCrLf & "付けたい名前を変更して再度実行してください。" QTSonzaiChk01 = 1 Exit Function End If End Function '############################################################################### '指定されたブック内に、指定された名前を含むQueryTableオブジェクトが '存在するかどうかをチェックする関数。 '上記関数の「QTSonzaiChk01」から予備だされます。 'なお、戻り値をVariant型の配列にしてあります。 ' '戻り値→(チェックする名前,それを含んだ実際のQTの名前,見つかったシート名)の ' Variant型の配列。 ' '############################################################################### Function KizonQTCheck01(o_WBjj As Workbook, s_ChkQTNm01jj As String) As Variant Dim o_KizonQT01jj As QueryTable Dim o_KizonWSjj As Worksheet Dim i_EscapeForFlg As Integer '★ 設定部 Set o_WBjj = ThisWorkbook i_EscapeForFlg = 0 KizonQTCheck01 = Array("OK", "OK", "OK") '↑検索がヒットしなかったときの戻り値をあらかじめ設定しておく。 ' ヒットすれば、この値が別の配列で上書きされる。 ' ※配列で返したい+初期値を決めておきたいときは、 ' あらかじめ配列で初期値を埋めておかないと、 ' 呼び出し元のプロシージャ側にての、戻り値でのIf文の判断分岐等々にて、 ' 「型が違います」のエラーになるので注意する。 ' でも、もっとスマートなやり方があるかもしれない。 '★ 実動部 For Each o_KizonWSjj In o_WBjj.Worksheets '指定されたQueryTableオブジェクトが存在するかを探すために、 '全シートを移動するループ。親ループ。 ' Debug.Print o_KizonWSjj.Name If i_EscapeForFlg = 1 Then Exit For 'もしヒットしたら、この(全部のシートを順に移動していくという)親ループも抜ける。 '※「i_EscapeForFlg」が1になっていたら、ヒットした、という意味。 For Each o_KizonQT01jj In o_KizonWSjj.QueryTables '各シートの中のすべてのQueryTableオブジェクトを 'チェックするループ。子ループ。 ' Debug.Print o_KizonQT01jj.Name If 1 <= InStr(1, o_KizonQT01jj.Name, _ s_ChkQTNm01jj, _ vbBinaryCompare) Then '↑目的のQTオブジェクトがヒットした時はこれ以降↓の処理をする。 ' 目的の名前が含まれたQTオブジェクトがヒットしたとき↓。 ' Debug.Print "探しているQueryTableオブジェクトがありました。---" & o_KizonQT01jj.Name If Not (o_KizonWSjj Is ActiveSheet) Then 'もし、目的の名前のQTオブジェクトが見つかったシートが、 'アクティブなシート「以外」であれば、「ヒットした!」と 'みなして以下の処理。 'アクティブなシートに目的のQTオブジェクトが存在してしまっていたなら、 'そのQTは「消しちゃってもいい」ということにして、 '「ヒットしなかったもの」とみなす。 KizonQTCheck01 = Array( _ s_ChkQTNm01jj, _ o_KizonQT01jj.Name, _ o_KizonWSjj.Name) ' ↑ 戻り値(OK・OK・OK)を、ヒット内容に上書き。 i_EscapeForFlg = 1 'ヒットしたことを、親ループを抜けるために、メモ。 Exit For 'この(シート内の全てのQTオブジェクトを調べるという)子ループを抜ける。 Else End If Else ' Debug.Print "探しているQueryTableオブジェクトはありません。" End If Next Next End Function '############################################################################### ' '「テーブル機能」は使わずに、つまり、QueryTableオブジェクトを埋め込まないパターン。 'そして、他の「XLS、XLSM、XLSX」や自ファイルのシートなどを吸い込む関数のサンプル。 ' '前述の1つ目と同様に、「Microsoft Query」での結合をマクロの記録機能で記録して、<a href="https://euc-access-excel-db.com/tips/ct90_yougo/yougo-sql01" target="_blank" rel="noopener noreferrer">SQL</a>を少し '短くしただけのコードを、「テーブル機能」に埋め込まないように2行ほど書き換えたもの、を、 '関数化したもの。 ' 'これは「QueryTableオブジェクト」のみで結果を表示しています。 'なお、「Microsoft Query」は、実はExcelからは独立した機能ですが、<a href="https://euc-access-excel-db.com/tips/ct90_yougo/yougo-sql01" target="_blank" rel="noopener noreferrer">SQL</a>実行の結果の表は、 '「QeryTableオブジェクト」に返ってくるように、Excel自身が指示を出しているっぽいです。 'なので、「Microsoft Query」と「QueryTableオブジェクト操作」は、機能は操作は異なりますが、 '結果は「QueryTableオブジェクト」に出力される、「同等なもの」と理解して良さそうです。 ' ' ' 呼び出し方法 ' Call MSQryOnlMakeByODBCFunc001("読みに行きたいファイルのフルパス", ' "そのファイルの在るフォルダのパス", ' SQL文, ' 結果表(QueryTableオブジェクト)につけたい名前, ' 結果を出力したい「オブジェクトとしての」シート. ' 結果表を出力するセルのアドレス(表の一番左上隅のセルの。) ' ' ' 例:実際には各行に、「 _ 」(半角での、スペース+アンダーバー)が要ります。 ' ' Call MSQryOnlMakeByODBCFunc001("D:\1\クエリのネストのテスト.xls", ' "D:\1", ' s_SqlStr01jj, ' "QT_To_OwnSheet1", ' ActiveSheet, ' "$A$1") ' '############################################################################### Sub MSQryOnlMakeByODBCFunc001(s_TrgFNm01jj As String, _ s_TrgFPath01jj As String, _ s_Sql01jj As String, _ s_QTNm01jj As String, _ o_ImpWSht01jj As Worksheet, _ s_ImpRng01jj As String) On Error GoTo error1: Dim o_QT01jj As QueryTable Dim i_Answ01 As Integer '★ チェック部 '最後のチェック i_Answ01 = MsgBox("本当にQueryTableオブジェクトを作成or書き換えてもいいですか?", vbOKCancel) If i_Answ01 = 2 Then Exit Sub '「いいえ」が押されたら終わる。 Else 'それ以外は終わらない。以降の処理を続ける。。 End If '★ 実動部 'すでにある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 'QueryTableオブジェクトの生成 Set o_QT01jj = o_ImpWSht01jj.QueryTables _ .Add(Connection:= _ "ODBC;DSN=Excel Files" & _ ";DBQ=" & s_TrgFNm01jj & _ ";DefaultDir=" & s_TrgFPath01jj & _ ";DriverId=1046" & _ ";MaxBufferSize=2048" & _ ";PageTimeout=5" & _ ";" _ , Destination:=o_ImpWSht01jj.Range(s_ImpRng01jj)) With o_QT01jj .CommandText = Array(s_Sql01jj) .RowNumbers = False .FillAdjacentFormulas = False .PreserveFormatting = True .RefreshOnFileOpen = False .BackgroundQuery = True .RefreshStyle = xlInsertDeleteCells .SavePassword = False .SaveData = True .AdjustColumnWidth = True .RefreshPeriod = 0 .PreserveColumnInfo = True ' .ListObject.DisplayName = "テーブル_Excel_Files_からのクエリ4" '↑この2つ目のサンプルコードは新しいExcelでも もちろん動きますが、 ' もともとは古いバージョンのExcelのためのものです。 ' しかしこの行だけは新しいExcelのためのものです。 ' 古いExcelは、最初から「テーブル機能」が使えないので ' 古いExcelでこの2つ目のサンプルを動かすとこの行はエラーになります。 ' なので、コメントアウトして、代わりに以下の行で名前を設定しています。 .Name = s_QTNm01jj .Refresh BackgroundQuery:=False 'INSERT や UPDATEなどでエラーにはなるが、一応実行は完了する。SQLどおりに。 End With 'アクティブウィンドウの調整 ActiveWindow.Zoom = 75 'ズーム 75% o_ImpWSht01jj.Range("A2").Select ActiveWindow.FreezePanes = True 'ウィンドウ枠の固定 Exit Sub error1: If Err.Number = 1004 Then '「o_QT01jj.Refresh BackgroundQuery:==False」で1004番の '「アプリケーション定義またはオブジェクト定義のエラーです。」という 'エラーになった時の処理。 'SELECT系の命令じゃない時(INSERTやUPDATEなどを使った時)に、 '1004エラーになるので、その回避。 '↓エラーが出てもSQLの結果が正常に適用されるようなのでこの1文は不要になってしまった。 ' o_QT01jj.Refresh BackgroundQuery:=True 'True(非同期)でSQLを実行。Falseだと「同期」で、「同期」だと、他のプログラムの並列動作は無い。Trueだと「非同期」=他のプログラムも同時進行してしまう。けど、一応実行はできる。 Debug.Print Err.Description Resume Next Else End If End Sub '############################################################################### 'Excelを開かずに、Excelのシート名(テーブル名)を調べる関数 '「sn」は「SheetName」の略です。 'イミディエイトウィンドウでさっと調べたいのであえて短い名前にしてあります。 ' ※なお、数十万件もあるExcelファイルを覗きにいく(調べに行く)ときは、 ' 結果が出るまで十数秒か数十秒、あるいは数分、かかります。 '############################################################################### Function sn(s_BkFlpath As String) 'http://doctorlabo.main.jp/?p=398 を加工。 ' Dim s_BkFlpath As String Dim i As Long ' '以下の変数設定を使いたい時は、 ' 'VBEの画面にて、以下の2つのライブラリへの「参照設定」が必要です。 ' '・Microsoft ActiveX Data Object 2.8 Library ' '・Microsoft ADO Ext.2.8 for DDL and Security] ' Dim cn As New ADODB.Connection ' Dim t As Table ' Dim ct As New ADOX.Catalog '「参照設定」をしたくないときは以下の変数設定を使います。 Dim cn As Object Dim t As Object Dim ct As Object On Error GoTo error1: '★ 設定部 '「参照設定」をしたくないときの「ADO」の準備設定 '設定が空の(=未設定の)ADO用の変数の用意 Set cn = CreateObject("ADODB.Connection") '設定が空の(=未設定の)ADOX用の変数の用意 Set ct = CreateObject("ADOX.Catalog") '※「参照設定」をしたときは、直上のようなコードは不要です。 ' cn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & ThisWorkbook.path & "\基本.mdb" & ";" ' s_BkFlpath = "D:\1\5.xls" ' cn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & s_BkFlpath & ";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1""" ' cn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & s_BkFlpath & ";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1""" 'ExcelファイルへのADO形式での接続 If 0 < InStr(1, s_BkFlpath, ".xlsm", vbBinaryCompare) Then cn.Open "Provider=Microsoft.ACE.OLEDB.12.0" & _ ";Data Source=" & s_BkFlpath & _ ";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1""" ElseIf 0 < InStr(1, s_BkFlpath, ".xlsx", vbBinaryCompare) Then cn.Open "Provider=Microsoft.ACE.OLEDB.12.0" & _ ";Data Source=" & s_BkFlpath & _ ";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1""" ElseIf 0 < InStr(1, s_BkFlpath, ".xls", vbBinaryCompare) Then '最初にxlsを調べてしまうと、 'xlsmとxlsxにも反応してしまうので一番最後に調べる cn.Open "Provider=Microsoft.Jet.OLEDB.4.0" & _ ";Data Source=" & s_BkFlpath & _ ";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1""" Else End If 'ADO形式で接続したExcelファイルにおいて、 '「ADOX」の機能を使えるようにする。 ct.ActiveConnection = cn ' ↑ ' 「ADOX」は、ADO接続をした場合に限り、 ' 「テーブルを作成したり削除したりする」機能です。 ' ' ※「ADO」ではなく、「DAO」での接続を使いたい場合では、 ' 「テーブルを作成したり削除したりする機能」は、 ' 最初からその「DAO」単体の中に含まれているため、 ' このような処理(=コード)は必要ありません。 '★ 実動部 ' ActiveSheet.Cells.Clear 'すべてのシート名をチェック For Each t In ct.Tables ' If t.Type = "TABLE" Then ' i = i + 1 ' ActiveSheet.Cells(i, 1).Value = t.Name ' End If Debug.Print t.Name Next t cn.Close Set cn = Nothing Set ct = Nothing Exit Function error1: cn.Close Set cn = Nothing Set ct = Nothing End Function '############################################################################### 'Excelを開かずに、Excelのシート名(テーブル名)と列名を調べる関数 '「sn2」は「SheetName2」の略です。 'イミディエイトウィンドウでさっと調べたいのであえて短い名前にしてあります。 ' ※なお、数十万件もあるExcelファイルを覗きにいく(調べに行く)ときは、 ' 結果が出るまで十数秒か数十秒、あるいは数分、かかります。 '############################################################################### Function sn2(s_BkFlpath As String) 'http://doctorlabo.main.jp/?p=398 を加工。 ' Dim s_BkFlpath As String Dim i As Long ' '以下の変数設定を使いたい時は、 ' 'VBEの画面にて、以下の2つのライブラリへの「参照設定」が必要です。 ' '・Microsoft ActiveX Data Object 2.8 Library ' '・Microsoft ADO Ext.2.8 for DDL and Security] ' Dim cn As New ADODB.Connection ' Dim t As Table ' Dim ct As New ADOX.Catalog '「参照設定」をしたくないときは以下の変数設定を使います。 Dim cn As Object Dim t As Object Dim ct As Object On Error GoTo error1: '★ 設定部 '「参照設定」をしたくないときの「ADO」の準備設定 '設定が空の(=未設定の)ADO用の変数の用意 Set cn = CreateObject("ADODB.Connection") '設定が空の(=未設定の)ADOX用の変数の用意 Set ct = CreateObject("ADOX.Catalog") '※「参照設定」をしたときは、直上のようなコードは不要です。 ' cn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & ThisWorkbook.path & "\基本.mdb" & ";" ' s_BkFlpath = "D:\1\5.xls" ' cn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & s_BkFlpath & ";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1""" ' cn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & s_BkFlpath & ";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1""" 'ExcelファイルへのADO形式での接続 If 0 < InStr(1, s_BkFlpath, ".xlsm", vbBinaryCompare) Then cn.Open "Provider=Microsoft.ACE.OLEDB.12.0" & _ ";Data Source=" & s_BkFlpath & _ ";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1""" ElseIf 0 < InStr(1, s_BkFlpath, ".xlsx", vbBinaryCompare) Then cn.Open "Provider=Microsoft.ACE.OLEDB.12.0" & _ ";Data Source=" & s_BkFlpath & _ ";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1""" ElseIf 0 < InStr(1, s_BkFlpath, ".xls", vbBinaryCompare) Then '最初にxlsを調べてしまうと、 'xlsmとxlsxにも反応してしまうので一番最後に調べる cn.Open "Provider=Microsoft.Jet.OLEDB.4.0" & _ ";Data Source=" & s_BkFlpath & _ ";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1""" Else End If 'ADO形式で接続したExcelファイルにおいて、 '「ADOX」の機能を使えるようにする。 ct.ActiveConnection = cn ' ↑ ' 「ADOX」は、ADO接続をした場合に限り、 ' 「テーブルを作成したり削除したりする」機能です。 ' ' ※「ADO」ではなく、「DAO」での接続を使いたい場合では、 ' 「テーブルを作成したり削除したりする機能」は、 ' 最初からその「DAO」単体の中に含まれているため、 ' このような処理(=コード)は必要ありません。 '★ 実動部 ' ActiveSheet.Cells.Clear Debug.Print "★★★★★★★★★★★★★★★" 'すべてのシート名をチェック(シート名のみ先に全部出す。) For Each t In ct.Tables ' If t.Type = "TABLE" Then ' i = i + 1 ' ActiveSheet.Cells(i, 1).Value = t.Name ' End If Debug.Print t.Name Next t Debug.Print "★★★★★★★★★★★★★★★" Debug.Print "=============================" Dim f01 As Object 'すべてのシート名とそのシートの列名を一覧する。 For Each t In ct.Tables ' If t.Type = "TABLE" Then ' i = i + 1 ' ActiveSheet.Cells(i, 1).Value = t.Name ' End If Debug.Print t.Name ' Debug.Print "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" Debug.Print "------------------------" For Each f01 In t.Columns Debug.Print f01.Name Next Debug.Print "=============================" Next t cn.Close Set cn = Nothing Set ct = Nothing Exit Function error1: cn.Close Set cn = Nothing Set ct = Nothing End Function ' ' |
パラメータクエリを作成したい場合は、SQL文の条件に半角の「?」を使います。
「(列名 Like ?)」とか「(列名 = ?)」「(列名 Between ? And ?)」とか、そんな形で使います。
(この「(列名 Like ?)」とか「(列名 = ?)」というのを「節」と呼ぶようです。ヘルプに書いてありました。)
複数のパラメータを使いたいときは、その数だけ「?」を使います。
パラメータの順番は先に書いたものから順番に、1、2、3、・・・・となります。
もう少し具体的に書くと、「?」を書いた順番に・・・、
ActiveSheet.QueryTables(1).Parameters(1)
ActiveSheet.QueryTables(1).Parameters(2)
ActiveSheet.QueryTables(1).Parameters(3)
・
・
・
・・・・と続いて作られていく・・・・という意味です。
「Between」などでは「?」を2つ使いますが、その中でも1つ目、2つ目、というかたちになります。
作ったパラメータは、実際のQueryTableオブジェクトでは、
QueryTableオブジェクトの右クリック→「パラメーター」でGUI画面で確認することができます。
なお、パラメータクエリは、格納場所を変えると壊れるかもしれません。
その際は、またSQLを使って
================================
例えば、以下のようなSQLを作ったとします。
strSql01 = ""
strSql01 = strSql01 & "SELECT * "
strSql01 = strSql01 & " FROM Sheet1$
Sheet1$
"
strSql01 = strSql01 & " WHERE ( 顧客ID=? ) AND ( 単価>=? );"
この場合(演算子等々にかかわらず、とにかく)、「?」が2つあるので、「パラメータを2つ作りたい」、という意味になります。
で、以降が、その際の、パラメータの作り方と、パラメータの値の入力方法の設定です。
以降のプログラムの例だと、以下のような設定となります。
・「顧客ID」のパラメータを「param1」で作り、
「J1」セルを入力箇所に設定+自動更新可能にする。
・「単価」のパラメータを「param2」で作り、
「J2」セルを入力箇所に設定+自動更新可能にする。
なお、以下のなかで、「Qt_MeQtbl01」はすでに作成された空のQueryTableオブジェクトです。
また、パラメータを作成する前に、必ず、「?」を含むSQL文を、QueryTableオブジェクトにセットしておきます。
「s_SQLStr01 = "SELECT * FROM [Sheet1$] WHERE (列名 = ?)」
「qt.Sql = s_SQLStr01 」
みたいな形で。
'1つめのパラメータの作成
Dim param1 As Parameter
Set param1 = Qt_MeQtbl01.Parameters.Add("prm1", xlParamTypeNumeric) '「数値型」のパラメータの作成
param1.SetParam xlRange, ActiveSheet.Range("J1") 'パラメータの入力箇所を「J1」セルとする。
'※Parameters.Addメソッドの第一引数の「 "prm1" 」は、作ったパラメータを特定するための名前です。
' この例なら「prm顧客ID」とか「顧客IDprm」とかにしてもとしてもOKです。
' また、「xlParamTypeNumeric」などのように、型の指定を正しくしないと
' エラーになります。
' 「?」の列のデータ型と必ず一致するように、ここは常に変えていかなくてはなりません。
'2つめのパラメータの作成
Dim param2 As Parameter
Set param2 = Qt_MeQtbl01.Parameters.Add("prm2", xlParamTypeNumeric)
param2.SetParam xlRange, ActiveSheet.Range("J2")
'※"prm2"も同様で、今回の例なら「prm単価」「単価prm」などとしてもOKです。
Qt_MeQtbl01.CommandText = vrtSql01 'SQL文を設定
Qt_MeQtbl01.Refresh 'SQL文の実行と反映
'セルパラメータの自動更新設定
'セルのパラメータの値を変更したと同時にクエリが自動更新されるようにする
'1回、QueryTableオブジェクトが作成されてRefreshされてからじゃないと
'エラーになる。
param1.RefreshOnChange = True
param2.RefreshOnChange = True
'ヘルプの事例は、すでに作成されたQueryTableオブジェクトに
'対してこの処理をしているか、Refesh前にやっている。
'本当にRefesh前にこの設定を入れても問題ないかは未確認。
'もしかしたら、エラーになるかもしれない。
=============
※パラメータ用のセルを作る場所について
本記事の例では、パラメータ用のセルをQueryTableオブジェクトを生成するシートと同じシートに作ってしまっていますが、できれば、パラメータのセルは、他のシートのセルにしたほうが無難かと思います。
でないと、QueryTableオブジェクトができたときに、パラメータ用のセルがQueryTableオブジェクトの範囲に上書きされたしまう可能性があるためです。また、生成されたQueryTableオブジェクトの結果に、さらにQueryTableオブジェクトをかけたい時に、パラメータ用のセルが原因で動作不良を起こすとも限りません。
未確認なので、ご自身でも一度試してみていただきたいのですが、そんな感じで、一応、本番ではパラメータ用のセルは別のシートに作ったほうがいいと思います。(パラメータセル専用のシートを設けるなどして。)
もちろん、「テスト段階」では同じシートに作ってもいいと思います。
'パラメータの個数の調査
? Worksheets("MsQRY吸込").QueryTables(1).Parameters.count
1
'パラメータの削除
'(パラメータの削除だけなので、QueryTableオブジェクトは残ります。
Worksheets("シート名").QueryTables(1).Parameters.delete
'パラメータのセルアドレスのチェック
? Worksheets("シート名").QueryTables(1).Parameters(1).SourceRange.Address
$F$3
$F$2
$F$2
'既に作成されたQueryTableオブジェクトの、
'パラメータのセルアドレス「だけ」の変更?・・・と思いきや、エラーでできませんでした。
' ↓ ※このプログラムは動きません。
Worksheets("シート名").QueryTables(1).Parameters(1).SourceRange.Address = "$F$3"
'それをやるには、ヘルプによると、以下のように.SetParamwメソッドだけを普通に使えばいいようです。
Worksheets("シート名").QueryTables(1).Parameters(1).SetParam xlRange, Range("J5")
'これはたとえば「G2」セルが1つ目のパラメータの入力セルだった場合に、それを「J5」セルに変更します。
'このとき、セルに値を中途半端に入れたり、型の違う値を入れたりするとエラーになることがありますが、OK、OK、してしまえば大丈夫です。そのあと正しい値をセルに入力してください。
'条件通りに、表が変化します。
なので、以降にあげた、「★ パラメータクエリをVBAで自動作成するプログラム例」でも、既存のQueryTableオブジェクトのパラメータのセル位置を変えたい場合は、「SQLを変えないでおいても」そのまま、このコードが使えます。
=============
'以下、色々とテスト。イミディエイトウィンドウにて。
? qt.Parameters(1).SourceRange.Address
$F$2
qt.Parameters(1).SourceRange.Address = "$F$3"
? Worksheets("MsQRY吸込").QueryTables(1).name
ExternalData_1
1
1
SELECT Sheet1$
.連番, Sheet1$
.顧客ID, Sheet1$
.数量, Sheet1$
.単価
FROM Sheet1$
Sheet1$
WHERE (Sheet1$
.顧客ID=?)
? Worksheets("MsQRY吸込").QueryTables.item(1).PostText
================
このプログラムの内容を、冒頭のダウンロードサンプルに追加してもよいと思います。
独立したプログラムにして、いったん作成されたクエリに対して、SQLの更新とともにおこなうようにすればいいと思います。
既存のプログラムの「プロシージャ内」に組み込むとすごく面倒くさいことになる気がしますので・・・。
是非、ご自分でもチャレンジしてみてください。
※本記事のここでのサンプルでは、「セルの値」をパラメータの値にする方法(xlRange)をとっています。(「XlParameterType 列挙」の「xlRange」。)
が、VBAのインプットボックス(Inputbox関数)の戻り値(指定しないと数字も文字列型)を使うやりかたなどもあるようです。
本記事のサンプルができあがってから、少し調べてみたら、以下のURLのような記事が見つかりました。
https://www.moug.net/tech/exvba/0060038.html
このWebページのサンプルでは、「type:=xlConstant(xlConstant=1= 引数 Value により指定された値を使用します。)」を使って、単純に、Inputbox関数の戻り値を使っています。
Inputbox関数は何も指定しないと数字や日付であっても文字列型として返ってきてしまうので、もしそれを使って、「型が違う」とQueryTableオブジェクトに怒られたら、このサイトのサンプルのようにInputboxで戻り値の型を指定したほうがいいかもしれません。
SQLのパラメータの入力値は、そのデータ型が「?」の列と同じデータ型でないと、「データ型がおかしいよ!」とエラーになりますので・・。
逆に、もし怒られなかったら問題ありません。(無い気もしますが・・・)
といいますか、↑このサイトのやり方よりも、「xlPrompt」を使うほうが手軽かもです。
QueryTableオブジェクトを右クリックして「更新」したときに、パラメータ値を入力するダイアログが出てくれるので・・・。「?」で作った数だけ、ダイアログが出てくれます。
またそのダイアログでは、入力した値をいちいちデータ型チェックや変換をする必要もありません。(入力値のデータ型を自動認識してくれます。)
あと、このサイトのやりかたでは、右クリックで「更新」したときに何も出ないかも・・・。よくわかりませんけど・・・。(出ても、どっかにボタン作成が要る?かもなのでめんどくさそうです。)
(しかし、このサイトは・・・、ここまでやっているなら、もっとSQLを広めればいいのに、と思ってしまいます。しかも、もっと、ちゃんとParameterオブジェクトの解説をすればいいのに・・・。なぜこの大御所サイトはしないのだろう???意味がわかりません。
VBAの「ループ処理だけが目的」「VBAが使えるぞすごいだろう?」「SQLなんていらないよ」という感じで、「計算や集計はどうでもいい」、プログラム作り・管理の「コスパ」なんて「どうでもいいだろ?」と言っているように見えてしまいます。
こういうのが「コスパが悪化する無駄なVBA・ワークシート関数を増やす原因」なんだと思います。過去によくお世話になっていただけに、いまだにこうなんだとガッカリします。
「AccessVBAなんてどうでもいい」とはもちろん言いませんが、でもExcelVBAをここまでやられているなら、「ExcelでのSQL」や「Microsoft Query」の操作も同時にもっとやればいいのに・・・と思ってしまいます。どうせAccessでSQLやることになるんですから・・・。
大御所サイトだからこそ、もっと、「複雑な条件での」「表計算・集計・リストアップ」、また、「表計算ソフトそのもの」「ビジネス応用そのもの」の「本質を」、やってほしいです。VBAでループ処理ができることだけが偉いわけではまったくもって、ありませんので・・・。)
そのほか、Parameterオブジェクトでは、前述しましたように、
Parameter.SetParam メソッドの「XlParameterType 列挙」にて、
「xlPrompt=0=値の入力を促すダイアログ ボックスを表示します。引数 Value はダイアログ ボックスに表示する文字列を指定します。 」
も使えます。
ヘルプを読めば全部書いてあります。
【参考】XlParameterDataType 列挙 の値
「SQLの中の、抽出条件に「?」を付けた列のデータ型」と必ず合致するように、以下のデータ型のどれかに毎回必ず変更します。
名前-----値-----説明
xlParamTypeBigInt------5-----多倍長整数型
xlParamTypeBinary------2-----バイナリ型
xlParamTypeBit------7-----ビット型
xlParamTypeChar-----1-----文字列型
xlParamTypeDate-----9-----日付型
xlParamTypeDecimal-----3-----小数点型
xlParamTypeDouble-----8-----二重型
xlParamTypeFloat-----6-----浮動小数点型
xlParamTypeInteger-----4-----整数型
xlParamTypeLongVarBinary------4-----長バイナリ型
xlParamTypeLongVarChar------1-----長文字型
xlParamTypeNumeric-----2-----数値型
xlParamTypeReal-----7-----リアル型
xlParamTypeSmallInt-----5-----小整数型
xlParamTypeTime-----10-----時刻型
xlParamTypeTimestamp-----11-----タイムスタンプ型
xlParamTypeTinyInt------6-----極小整数型
xlParamTypeUnknown-----0-----不明な種類
xlParamTypeVarBinary------3-----可変長バイナリ型
xlParamTypeVarChar-----12-----可変長文字列型
xlParamTypeWChar------8-----Unicode文字列型
▼ 「すでに作成されたQueryTableオブジェクト」に対して、パラメータを作成する例3つ(1個、2個、3個のパラメータの場合の例)
冒頭のサンプルファイル(xlsm、xls)に追加するなら、このプログラムが一番簡単かと思います。
各シートのモジュールにコピペして使ってみてください。
パラメータが無い既存のQueryTableオブジェクトの場合は、「?」を使ってSQL自体も変更します。
すでにパラメータが作ってあるQueryTableオブジェクトの場合は、SQLは変更せず、セル位置などだけを変更することもできます。(少し作り変えが必要ですが。)
なお、セルの値を使ったパラメータクエリは、VBAで自同生成したときに、そのセルの値が空白だと、SQL内容が正常でも「1004 エラー」になるようです。
なので、以降のプログラムでは「1」をダミーデータとしてセルに自動セットする形にしてあります。「1」なら、Excelの場合に限っては、日付、時刻、数値、文字、色々なデータ型に対応できるかな・・・と思いまして・・・。
ただこれは「とりあえずエラーにならないようにというだけのこと」なので、QueryTableオブジェクトができあがったら、本来のパラメータの値を入力しなおしてください。
もちろん、どのセルをパラメータ値の入力箇所にするか、最初からわかってはいるわけですので、本来のデータ型の値をあらかじめ、そのセルに入力しておけば なおいいです。
ただし、全角半角の入力ミスが無いように注意が必要です。
正しいデータ型の値が入っていれば、列名+レコード表示されますし
「1」のダミーデータなら、列名だけが表示されます。
以下のサンプルは「1つだけのパラメータを作る・セル位置を変える」などに使えますが、「2つ以上」には対応していません。
なので、2つ以上のパラメータを作成したい場合は、これ以降のサンプルもご参考にしてください。
注意
QueryTableオブジェクトを作ったときのSQLと、このプログラムのSQLのファイルやテーブル名が異なることがないようにします。
あと、以下のところの修正は、必ず、SQLの「?」のデータ型に合わせてAddメソッドの「xlParamTypeChar」の部分を書き換えます。データ型は、Parameters.Addメソッドのヘルプの、「XlParameterDataType 列挙」のリンクに書いてあります。
s_PrmNm1 = "具Prm"
Set Param1 = qt.Parameters.Add(s_PrmNm1, xlParamTypeChar) '変える
Set o_ParamRange1 = Worksheets("sheet1").Range("G2") '変える。
Param1.SetParam xlRange, o_ParamRange1
Param1.RefreshOnChange = True
o_ParamRange1.Interior.Color = vbYellow
o_ParamRange1.Offset(0, 1).Value = "具Prm" '状況によって変える。(特にBetween)
o_ParamRange1.Value = "%" '好きなダミーデータを入れる
'(目的のデータ型に合ったものを)
パラメータが2つ、3つ、と増えたら、増やしたものについては、
・ s_PrmNm1 、
・ Param1 、
・ o_ParamRange1 、
の、番号も変えます。
(あらかじめ、テキストエディタに上記の8行をコピペ―しておき、テキストエディタの置換機能で置換し、コピペし戻せばOKかと思います。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
' ' Sub CangeQramQueryOnePrm01() Dim qt As QueryTable Dim s_SQLStr01 As String Dim Param1 As Parameter Dim o_ParamRange1 As Range Dim s_PrmNm1 As String On Error GoTo error1: '★ 設定部 Set qt = Worksheets("sheet1").QueryTables(1) '既存のQueryTableオブジェクトの選定(=取得) s_SQLStr01 = qt.Sql 'SQL文をコメントアウトしたときのための、初期値としてのSQL文の設定 'パラメータの設定は、★実動部で全部一度にやる。 'データ型の指定やセル位置など、そこそこ設定する項目が多いため 'プログラムの中で上下に分かれると設定が面倒なため。 '★ 先にチェック部 'もし、すでにパラメータの設定があったら 'いったんそれを削除する。 If 1 <= qt.Parameters.Count Then qt.Parameters.Delete 'すべてのパラメータをいったん削除 Else End If 'SQLの設定。 'ここをコメントアウトすると、セルの位置だけの変更ができます。 '' '完全一致の場合のSQLの例 ' s_SQLStr01 = "SELECT * FROM `Sheet1$` WHERE (具 = ?)" ' '部分一致の条件のSQLの例 ' s_SQLStr01 = "SELECT * FROM `Sheet1$` WHERE (具 Like ?)" s_SQLStr01 = "" s_SQLStr01 = s_SQLStr01 & "SELECT" s_SQLStr01 = s_SQLStr01 & " *" s_SQLStr01 = s_SQLStr01 & " FROM" s_SQLStr01 = s_SQLStr01 & " `Sheet1$`" s_SQLStr01 = s_SQLStr01 & " WHERE" s_SQLStr01 = s_SQLStr01 & " (具 Like ?)" '↑「Like」を使った場合は、セル側で「%語句%」と「%」で囲んだり、 ' 「%」を末尾につけたりして、絞り込みします。 ' この場合、セル側で「%」だけを打つとすべてのデータが表示されます。 ' 「?」を3つ使ってますので、 ' パラメータとしては3つ分の設定が要ります。 ' 先にSQLを書いてから、パラメータ用の変数と ' パラメータオブジェクトの設定を増やしたり減らしたり ' すればいいと思います。 '★ 実動部 '新しいSQL文に変更。 'パラメータクエリの場合は、 '基本的には、パラメータの設定よりも先に、 'SQL文をセットしないといけないっぽいです。 'SQL文の中の「?」がパラメータに相当するので 'それを先に作っておかないと、パラメータの '設定がそもそもできないのかも? 'よくわかりません。 qt.Sql = s_SQLStr01 '既存のQTオブジェクトに新しいSQL文のセット。 '1つめのパラメータの設定 s_PrmNm1 = "具Prm" 'パラメータクエリのパラメータ自体につける名前(パラメータ=Parameterはオブジェクトなので) Set Param1 = qt.Parameters.Add(s_PrmNm1, xlParamTypeChar) '1つめの新しいパラメータを「日付型」として作成。(SQLの「?」の内容の変更に伴い、XlParameterDataType 列挙のデータ型を指定。) Set o_ParamRange1 = Worksheets("sheet1").Range("G2") 'パラメータの値を入力したいセルの選定(=取得) Param1.SetParam xlRange, o_ParamRange1 'シートのセルを条件値の入力場所に設定。 Param1.RefreshOnChange = True 'セルの値を変更と同時に自動更新(自動反映)する設定。 o_ParamRange1.Interior.Color = vbYellow 'そのセルを黄色にする o_ParamRange1.Offset(0, 1).Value = "具Prm" o_ParamRange1.Value = "%" 'ダミーデータの入力。パラメータセルが空白なことでエラーになることの回避 qt.AdjustColumnWidth = False '列幅の自動調整をOFFに。 qt.Refresh '新しいSQLの内容通りに、更新の実行。 Exit Sub error1: If Err.Number = 1004 Then MsgBox "一応エラーになりましたが、" & vbCrLf & _ "SQL文は正しくて、「単にパラメータのセルに値が入っていないだけ」、かもしれません。 " & vbCrLf & _ "" & vbCrLf & _ "このまま続行しますので、パラメータの値を全部入れてみてください。" & vbCrLf & _ "" & vbCrLf & _ " ※最初のパラメータを入れてエラーになってもそれは正常です。" & vbCrLf & _ " そのまますべてのパラメータを入力し続けてください。" & vbCrLf & _ " (空白セルが残っているためにエラーになっているだけですので。)" & vbCrLf & _ "" & vbCrLf & _ " ただ、日付やワイルドカート(%など)は必ず半角で入力してください。" & vbCrLf & _ "" & vbCrLf & _ "もし全てのパラメータを入力していも表が変化しなかったら、" & vbCrLf & _ "まずSQL文を、次に、各種設定を見直してみてください。" Resume Next Else End If End Sub ' ' |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
' ' Sub CangeQramQueryTwoPrm01() Dim qt As QueryTable Dim s_SQLStr01 As String Dim Param1 As Parameter Dim o_ParamRange1 As Range Dim s_PrmNm1 As String Dim Param2 As Parameter Dim o_ParamRange2 As Range Dim s_PrmNm2 As String On Error GoTo error1: '★ 設定部 Set qt = Worksheets("sheet1").QueryTables(1) '既存のQueryTableオブジェクトの選定(=取得) s_SQLStr01 = qt.Sql 'SQL文をコメントアウトしたときのための、初期値としてのSQL文の設定 'パラメータの設定は、★実動部で全部一度にやる。 'データ型の指定やセル位置など、そこそこ設定する項目が多いため 'プログラムの中で上下に分かれると設定が面倒なため。 '★ 先にチェック部 'もし、すでにパラメータの設定があったら 'いったんそれを削除する。 If 1 <= qt.Parameters.Count Then qt.Parameters.Delete 'すべてのパラメータをいったん削除 Else End If '先にSQLの設定。 'ここをコメントアウトすると、セルの位置だけの変更ができます。 '' '完全一致の場合のSQLの例 ' s_SQLStr01 = "SELECT * FROM `Sheet1$` WHERE (具 = ? AND 名前 = ? )" ' '部分一致の条件のSQLの例' ' s_SQLStr01 = "SELECT * FROM `Sheet1$` WHERE (具 LIKE ? AND 名前 LIKE ? )" s_SQLStr01 = "" s_SQLStr01 = s_SQLStr01 & "SELECT" s_SQLStr01 = s_SQLStr01 & " *" s_SQLStr01 = s_SQLStr01 & " FROM" s_SQLStr01 = s_SQLStr01 & " `Sheet1$`" s_SQLStr01 = s_SQLStr01 & " WHERE" s_SQLStr01 = s_SQLStr01 & " (具 Like ? )" s_SQLStr01 = s_SQLStr01 & " AND (名前 Like ?)" '↑「Like」を使った場合は、セル側で「%語句%」と「%」で囲んだり、 ' 「%」を末尾につけたりして、絞り込みします。 ' この場合、セル側で「%」だけを打つとすべてのデータが表示されます。 ' 「?」を3つ使ってますので、 ' パラメータとしては3つ分の設定が要ります。 ' 先にSQLを書いてから、パラメータ用の変数と ' パラメータオブジェクトの設定を増やしたり減らしたり ' すればいいと思います。 '★ 実動部 '新しいSQL文に変更。 'パラメータクエリの場合は、 '基本的には、パラメータの設定よりも先に、 'SQL文をセットしないといけないっぽいです。 'SQL文の中の「?」がパラメータに相当するので 'それを先に作っておかないと、パラメータの '設定がそもそもできないのかも? 'よくわかりません。 qt.Sql = s_SQLStr01 '既存のQTオブジェクトに新しいSQL文のセット。 '1つめのパラメータの設定 Set Param1 = qt.Parameters.Add(s_PrmNm1, xlParamTypeChar) '1つめの新しいパラメータを「文字列型」として作成。(SQLの「?」の内容の変更に伴い、XlParameterDataType 列挙のデータ型を指定。) Set o_ParamRange1 = Worksheets("sheet1").Range("G2") 'パラメータの値を入力したいセルの選定(=取得) Param1.SetParam xlRange, o_ParamRange1 'シートのセルを条件値の入力場所に設定。 Param1.RefreshOnChange = True 'セルの値を変更と同時に自動更新(自動反映)する設定。 s_PrmNm1 = "具Prm" 'パラメータクエリのパラメータ自体につける名前(パラメータ=Parameterはオブジェクトなので) o_ParamRange1.Interior.Color = vbYellow 'そのセルを黄色にする o_ParamRange1.Offset(0, 1).Value = "具Prm" o_ParamRange1.Value = 1 'ダミーデータの入力。パラメータセルが空白なことでエラーになることの回避 '2つめのパラメータの設定 Set Param2 = qt.Parameters.Add(s_PrmNm2, xlParamTypeChar) '2つ目の新しいパラメータを「文字列型」として作成。(SQLの「?」の内容の変更に伴い、XlParameterDataType 列挙のデータ型を指定。) Set o_ParamRange2 = Worksheets("sheet1").Range("G3") 'パラメータの値を入力したいセルの選定(=取得) Param2.SetParam xlRange, o_ParamRange2 'シートのセルを条件値の入力場所に設定。 Param2.RefreshOnChange = True 'セルの値を変更と同時に自動更新(自動反映)する設定。 s_PrmNm2 = "名前Prm" 'パラメータクエリのパラメータ自体につける名前(パラメータ=Parameterはオブジェクトなので) o_ParamRange2.Interior.Color = vbCyan 'そのセルを蛍光ブルーにする o_ParamRange2.Offset(0, 1).Value = "名前Prm" o_ParamRange2.Value = 1 'ダミーデータの入力。パラメータセルが空白なことでエラーになることの回避 qt.AdjustColumnWidth = False qt.Refresh '新しいSQLの内容通りに、更新の実行。 Exit Sub error1: If Err.Number = 1004 Then MsgBox "一応エラーになりましたが、" & vbCrLf & _ "SQL文は正しくて、「単にパラメータのセルに値が入っていないだけ」、かもしれません。 " & vbCrLf & _ "" & vbCrLf & _ "このまま続行しますので、パラメータの値を全部入れてみてください。" & vbCrLf & _ "" & vbCrLf & _ " ※最初のパラメータを入れてエラーになってもそれは正常です。" & vbCrLf & _ " そのまますべてのパラメータを入力し続けてください。" & vbCrLf & _ " (空白セルが残っているためにエラーになっているだけですので。)" & vbCrLf & _ "" & vbCrLf & _ " ただ、日付やワイルドカート(%など)は必ず半角で入力してください。" & vbCrLf & _ "" & vbCrLf & _ "もし全てのパラメータを入力していも表が変化しなかったら、" & vbCrLf & _ "まずSQL文を、次に、各種設定を見直してみてください。" Resume Next Else End If End Sub ' ' |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
' ' Sub CangeQramQueryThreePrm01() Dim qt As QueryTable Dim s_SQLStr01 As String Dim Param1 As Parameter Dim o_ParamRange1 As Range Dim s_PrmNm1 As String Dim Param2 As Parameter Dim o_ParamRange2 As Range Dim s_PrmNm2 As String Dim Param3 As Parameter Dim o_ParamRange3 As Range Dim s_PrmNm3 As String On Error GoTo error1: '★ 設定部 Set qt = Worksheets("sheet1").QueryTables(1) '既存のQueryTableオブジェクトの選定(=取得) s_SQLStr01 = qt.Sql 'SQL文をコメントアウトしたときのための、初期値としてのSQL文の設定 'パラメータの設定は、★実動部で全部一度にやる。 'データ型の指定やセル位置など、そこそこ設定する項目が多いため 'プログラムの中で上下に分かれると設定が面倒なため。 '★ 先にチェック部 'もし、すでにパラメータの設定があったら 'いったんそれを削除する。 If 1 <= qt.Parameters.Count Then qt.Parameters.Delete 'すべてのパラメータをいったん削除 Else End If '先にSQLの設定。 'ここをコメントアウトすると、セルの位置だけの変更ができます。 '' '完全一致の場合のSQLの例 ' s_SQLStr01 = "SELECT * FROM `Sheet1$` WHERE ((予約日 Between ? And ?) AND (名前 = ?) )" ' '部分一致の条件のSQLの例 s_SQLStr01 = "" s_SQLStr01 = s_SQLStr01 & "SELECT" s_SQLStr01 = s_SQLStr01 & " *" s_SQLStr01 = s_SQLStr01 & " FROM" s_SQLStr01 = s_SQLStr01 & " `T_予約$`" s_SQLStr01 = s_SQLStr01 & " WHERE" s_SQLStr01 = s_SQLStr01 & " (予約日 Between ? And ?)" s_SQLStr01 = s_SQLStr01 & " AND (名前 Like ?)" '↑「Like」を使った場合は、セル側で「%語句%」と「%」で囲んだり、 ' 「%」を末尾につけたりして、絞り込みします。 ' この場合、セル側で「%」だけを打つとすべてのデータが表示されます。 ' 「?」を3つ使ってますので、 ' パラメータとしては3つ分の設定が要ります。 ' 先にSQLを書いてから、パラメータ用の変数と ' パラメータオブジェクトの設定を増やしたり減らしたり ' すればいいと思います。 '★ 実動部 '新しいSQL文に変更。 'パラメータクエリの場合は、 '基本的には、パラメータの設定よりも先に、 'SQL文をセットしないといけないっぽいです。 'SQL文の中の「?」がパラメータに相当するので 'それを先に作っておかないと、パラメータの '設定がそもそもできないのかも? 'よくわかりません。 qt.Sql = s_SQLStr01 '既存のQTオブジェクトに新しいSQL文のセット。 '1つめのパラメータの設定 s_PrmNm1 = "開始日Prm" 'パラメータクエリのパラメータ自体につける名前(パラメータ=Parameterはオブジェクトなので) Set Param1 = qt.Parameters.Add(s_PrmNm1, xlParamTypeDate) '1つめの新しいパラメータを「日付型」として作成。(SQLの「?」の内容の変更に伴い、XlParameterDataType 列挙のデータ型を指定。) Set o_ParamRange1 = Worksheets("sheet1").Range("G2") 'パラメータの値を入力したいセルの選定(=取得) Param1.SetParam xlRange, o_ParamRange1 'シートのセルを条件値の入力場所に設定。 Param1.RefreshOnChange = True 'セルの値を変更と同時に自動更新(自動反映)する設定。 o_ParamRange1.Interior.Color = vbYellow 'そのセルを黄色にする o_ParamRange1.Offset(0, 1).Value = "予約日の開始日Prm" o_ParamRange1.Value = 1 'ダミーデータの入力。パラメータセルが空白なことでエラーになることの回避 '2つめのパラメータの設定 s_PrmNm2 = "終了日Prm" 'パラメータクエリのパラメータ自体につける名前(パラメータ=Parameterはオブジェクトなので) Set Param2 = qt.Parameters.Add(s_PrmNm2, xlParamTypeDate) '2つ目の新しいパラメータを「日付型」として作成。(SQLの「?」の内容の変更に伴い、XlParameterDataType 列挙のデータ型を指定。) Set o_ParamRange2 = Worksheets("sheet1").Range("G3") 'パラメータの値を入力したいセルの選定(=取得) Param2.SetParam xlRange, o_ParamRange2 'シートのセルを条件値の入力場所に設定。 Param2.RefreshOnChange = True 'セルの値を変更と同時に自動更新(自動反映)する設定。 o_ParamRange2.Interior.Color = vbCyan 'そのセルを蛍光ブルーにする o_ParamRange2.Offset(0, 1).Value = "予約日の終了日Prm" o_ParamRange2.Value = 1 'ダミーデータの入力。パラメータセルが空白なことでエラーになることの回避 '3つめのパラメータの設定 s_PrmNm3 = "名前Prm" 'パラメータクエリのパラメータ自体につける名前(パラメータ=Parameterはオブジェクトなので) Set Param3 = qt.Parameters.Add(s_PrmNm3, xlParamTypeVarChar) '3つ目の新しいパラメータを「文字列型」として作成。(SQLの「?」の内容の変更に伴い、XlParameterDataType 列挙のデータ型を指定。) Set o_ParamRange3 = Worksheets("sheet1").Range("G4") 'パラメータの値を入力したいセルの選定(=取得) Param3.SetParam xlRange, o_ParamRange3 'シートのセルを条件値の入力場所に設定。 Param3.RefreshOnChange = True 'セルの値を変更と同時に自動更新(自動反映)する設定。 o_ParamRange3.Interior.Color = vbGreen 'そのセルを蛍光グリーンにする o_ParamRange3.Offset(0, 1).Value = "名前Prm" o_ParamRange3.Value = 1 'ダミーデータの入力。パラメータセルが空白なことでエラーになることの回避 qt.AdjustColumnWidth = False '列幅の自動調整をOFFに。 qt.Refresh '新しいSQLの内容通りに、更新の実行。 Exit Sub error1: If Err.Number = 1004 Then MsgBox "一応エラーになりましたが、" & vbCrLf & _ "SQL文は正しくて、「単にパラメータのセルに値が入っていないだけ」、かもしれません。 " & vbCrLf & _ "" & vbCrLf & _ "このまま続行しますので、パラメータの値を全部入れてみてください。" & vbCrLf & _ "" & vbCrLf & _ " ※最初のパラメータを入れてエラーになってもそれは正常です。" & vbCrLf & _ " そのまますべてのパラメータを入力し続けてください。" & vbCrLf & _ " (空白セルが残っているためにエラーになっているだけですので。)" & vbCrLf & _ "" & vbCrLf & _ " ただ、日付やワイルドカート(%など)は必ず半角で入力してください。" & vbCrLf & _ "" & vbCrLf & _ "もし全てのパラメータを入力していも表が変化しなかったら、" & vbCrLf & _ "まずSQL文を、次に、各種設定を見直してみてください。" Resume Next Else End If End Sub ' ' |
============
▼ そもそも「QueryTableオブジェクト自体」が作ってない場合のパラメータクエリの自動作成のプログラム例
このプログラムでは、2つのプロシージャを使っています。
これは2つめのプロシージャでパラメータを作っています。(ここでは2個を。)
冒頭のサンプルファイル(xlsm、xls)に2つめのプロシージャだけを組み込むときは、そのままでは使えませんので、2つめのプロシージャの、
「'★★★★★★★★★ パラメータが2つある場合の例 ★★★★★★★★★」
の部分周辺を見て、作り変える必要があります。
基本、『 ▼ 「すでに作成されたQueryTableオブジェクト」に対して、「1つだけ」のパラメータを作成する例 』を組み込んで1個バージョン、2個バージョン、3個おバージョンを作りこめば、こちらのプログラムは要らないのかな・・・、とも思います。
でも、一応、「ご参考」まで。
◎ 1つめ:パラメータ呼び出し元プロシージャ(2010でテストして動きました。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
' ' Sub MSQtest02() Dim strFullName As String '中身を覗きにいきたいファイルのフルパスを格納する変数。UNCパスも使えます。 Dim strFDPath As String 'そのファイルのフォルダパスのみを格納する変数。フルパスからファイル名を取り除いたものです。(最後の\は付いていてもいなくても大丈夫っぽいです。) Dim strSql01 As String '部分的なSQL文を格納するための変数です。句ごとか、文字数ごとに複数作成します。 Dim strSql02 As String '同上 Dim vrtSqlstr01 As Variant '部分的な複数のSQL文を最終的に1つに合体させるための変数です。SQLの実行の段階で、MicrosoftQuery(QueryTableオブジェクト)のCommandTextプロパティにこれを渡すのですが、それがVariant型であるため、ここでもVariant型を使います。 '*************************************************************************** '各種設定(MicrosoftQuery=QueryTableオブジェクトに渡すデータの一部) '*************************************************************************** ' strFullName = "D:\1\リレーションテストやSQLで使えるテーブルの範囲のテスト.xlsm" '覗きに行きたいファイルを指定 ' strFDPath = "D:\1" 'そのフォルダパスのみを指定 strFullName = ThisWorkbook.Path & "\" & ThisWorkbook.Name '覗きに行きたいファイルを指定 strFDPath = ThisWorkbook.Path '*************************************************************************** 'SQL文の作成(これもMicrosoftQuery=QueryTableオブジェクトに渡すデータの一部) '*************************************************************************** strSql01 = "" strSql01 = strSql01 & "SELECT * " strSql01 = strSql01 & " FROM `Sheet1$` `Sheet1$`" strSql01 = strSql01 & " WHERE ( 顧客ID=? ) AND( 単価>=? );" '*************************************************************************** 'SQL文の実行 '*************************************************************************** 'SQLをVariant型の変数に格納(代入)します。 vrtSqlstr01 = Array(strSql01, strSql02) '「vrtMakeMsqOwnFileTest01()」関数に、すべての設定を投げつけて、実行させます。 ' 'Sheet6に出力。 Call vrtMakeMsqOwnFileTest01(strFullName, strFDPath, "Sheet6", vrtSqlstr01) End Sub ' ' |
◎ 2つめ:呼び出されるプロシージャ(とりあえずこのサンプルプログラムでは、こちら側でパラメータを作ります。こっちらも2010で動きました。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
' ' '################################################################################################################################################################### '自ファイルの指定したシートに他ファイルのデータをMicrosoftQueryに読み込む関数 '(A1セルを起点に吸い込み) ' 'strSrcFullPath01 :読み込みたいファイルのフルパスを指定します。一応xlsmやxlsx。xlsの場合は"DriverId=1046;"を"DriverId=790;"に変えたほうがいいかもしれません。 'strSrcFdPath01 :読み込みたいファイルのフォルダパスを指定します。(ファイル名を除いたもの) 'strImpShtNm01 :吸い込みたい自ファイルのシートの名前を指定します。 'vrtSql01 :SQL文を指定します。 ' 句ごとか、一定の文字数(300文字ごとくらい)ごとの ' 配列として扱います。 ' SQLの実行の段階で、MicrosoftQuery(QueryTableオブジェクト)の ' CommandTextプロパティにこの変数に代入したSQL文を渡すのですが、 ' それが「Variant型」の「配列」であるため、 ' ここでもVariant型を使います。 ' '################################################################################################################################################################### Sub vrtMakeMsqOwnFileTest01(strSrcFullPath01 As String, _ strSrcFdPath01 As String, _ strImpShtNm01 As String, _ vrtSql01 As Variant) Dim Qt_MeQtbl01 As QueryTable Dim strCnn01 As String Dim Ws_MeSht01 As Worksheet '*********************************************************************************************************************************** '覗きに行くデータへの接続をするときの、接続文字列の設定。 '接続文字列が横に長くて見にくくなってしまうので、見やすく扱いやすく(書き換えやすく)します。 'いじるのは「DBQ」「DefaultDir」「DriverId」の3つです。DriverIdは「790」でもOKかもしれません。 ' '※設定値の参考Webページ ':https://docs.microsoft.com/ja-jp/sql/odbc/microsoft/odbc-jet-sqlconfigdatasource-excel-driver?view=sql-server-2017 '*********************************************************************************************************************************** strCnn01 = strCnn01 & "ODBC;" strCnn01 = strCnn01 & "DSN=Excel Files;" strCnn01 = strCnn01 & "DBQ=" & strSrcFullPath01 & ";" ' strCnn01 = strCnn01 & "DBQ=D:\1\リレーションテストやSQLで使えるテーブルの範囲のテスト.xlsm;" strCnn01 = strCnn01 & "DefaultDir=" & strSrcFdPath01 & ";" ' strCnn01 = strCnn01 & "DefaultDir=" & ThisWorkbook.Path & ";" strCnn01 = strCnn01 & "DriverId=1046;" '2010の場合? ' strCnn01 = strCnn01 & "DriverId=790;" '97、2000~2003の場合? strCnn01 = strCnn01 & "MaxBufferSize=2048;" strCnn01 = strCnn01 & "PageTimeout=5;" '******************************************************************************* 'もし指定したシートにMicrosoftQueryの結果の表(=QueryTablesオブジェクト)が '無かったら、作って表示させる処理。 '******************************************************************************* '吸い込む自ファイルのシートをオブジェクト変数に代入します。 Set Ws_MeSht01 = Application.ActiveWorkbook.Worksheets(strImpShtNm01) 'メインの処理 If (Ws_MeSht01.QueryTables.Count <= 0) Then '指定したシートにMicrosoftQueryの結果の表が何も無かったら作って終わる。 Set Qt_MeQtbl01 = Ws_MeSht01.QueryTables.Add( _ Connection:=strCnn01, _ Destination:=Ws_MeSht01.Range("A1")) '★★★★★★★★★ パラメータが2つある場合の例 ★★★★★★★★★ '1つめのパラメータの作成 Dim param1 As Parameter Set param1 = Qt_MeQtbl01.Parameters.Add("prm1", xlParamTypeNumeric) '数値型のパラメータの作成 param1.SetParam xlRange, ActiveSheet.Range("J1") 'パラメータの入力箇所を「J1」セルとする。 '2つめのパラメータの作成 Dim param2 As Parameter Set param2 = Qt_MeQtbl01.Parameters.Add("prm2", xlParamTypeNumeric) '数値型のパラメータの作成 param2.SetParam xlRange, ActiveSheet.Range("J2") 'パラメータの入力箇所を「J1」セルとする。 '★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ Qt_MeQtbl01.CommandText = vrtSql01 'SQL文を設定 Qt_MeQtbl01.Refresh 'SQL文の実行と反映 '★★★★★★ クエリの自動更新設定 ★★★★★★ 'セルのパラメータの値を変更したと同時にクエリが自動更新されるようにする '1回、QueryTableオブジェクトが作成されてRefreshされてからじゃないと 'エラーになる。 param1.RefreshOnChange = True param2.RefreshOnChange = True 'ヘルプの事例は、すでに作成されたQueryTableオブジェクトに '対してこの処理をしているか、Refesh前にやっている。 '本当にRefesh前にこの設定を入れても問題ないかは未確認。 'もしかしたら、エラーになるかもしれない。 '★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ Exit Sub '何もない状態から作ったので、プログラム自体をここで終わらせます。 Else 'もしすでに、指定したシートにMicrosoftQueryの結果の表が 'あったら何もしないで次へ。 End If '******************************************************************************* '既にMicrosoftQueryの表があったら、その SQL内容だけを書き換えて反映させる処理。 '******************************************************************************* Ws_MeSht01.QueryTables(1).CommandText = vrtSql01 'SQL文を設定 Ws_MeSht01.QueryTables(1).Refresh BackgroundQuery:=False 'SQLの実行と表示 End Sub ' ' |
- 投稿タグ
- 「ニセモノ」への道, 「本物」に近づくために, AccessVBA, Accessの独学, Access操作の基礎, Accesの独学, ADO/DAO, ExcelSQL, ExcelVBA, Excelの独学, Excel操作の基礎, Excel連携VBA, MicrosoftQuery, ODBC, SQL, パソコンでの自動化, マクロ, 独学, 自動化