Access2000VBA・Excel2000VBA独学~A表とB表の内容を(連番列以外の)「すべての列」で比較して、B表から、「重複しない行」を取り出す。(できたら、「抽出されたもの」について何かするために)
※まだ書きかけです。すみません。
※間違ってたらすみません。
※メモ書きなので、自分でも意味不明な箇所も多いです。ごめんなさい。
★ 目的
「A表:T99_社員マスタ」と「B表:t99_社員マスタ002」の内容を(連番列以外の)
「すべての列」で比較して、
「B表:t99_社員マスタ002」から、
「重複しない行」=「A表:T99_社員マスタと一致しない行」=「A表:T99_社員マスタと一致した行以外の行」、
を「B表:t99_社員マスタ002」から取り出す。
※連番列のみ、あるいは、全列を取り出す。
できたら、それを削除する。
汎用的な言い方だと・・・・
A表とB表の内容を(連番列以外の)
「すべての列」で比較して、
B表から、
「重複しない行」=「A表と一致しない行」=「A表と一致した行以外の行」、
を取り出す。
できたら、「抽出されたもの」について何かする。
・・・・という感じになります。
★ テーブル内容
例えば以下のような感じの内容の表を比較します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
' ' (A表)T99_社員マスタ 連番 社員番号 社員名 退社日付 入室ID 1 1 河村 加助 2019/03/16 5 2 2 鈴木 隆夫 2019/03/17 6 3 3 玉田 十夢 2019/03/18 7 4 4 三ツ矢 雄市 2019/03/19 8 (B表)t99_社員マスタ002 連番 社員番号 社員名 退社日付 入室ID 1 5 並木 佳野 2019/09/19 2 2 3 玉田 十夢 2019/03/18 7 3 6 田中 正志 2019/05/17 9 4 1 河村 加助 2019/03/16 5 ' ' |
この中では、「河村 加助」さん、「玉田 十夢」さんのレコード(行)が、
2つの表の中で(連番列以外の)全列の内容がまったく同じなので、
それ以外のデータを、「(B表)t99_社員マスタ002」から抽出する・・・、
というかたちになります。
★ ヒント(不一致の行だけを取り出す定型作業)
A表とB表の内容を(連番列以外の)
「すべての列」で比較して、
B表から、
「重複しない行」=「A表と一致しない行」=「A表と一致した行以外の行」、
を取り出す。
【不一致な B表のすべての列を表示させる例】
これは、「連番」という列がA表にもB表にもあることが大前提です。この列だけは内容が異なってもいい、という前提です。
(なので、あとから作り足してもOKです。)
なので、もし無ければ、先に、A表とB表の両方に「連番」という列を作ってから
以降のようなSQL文を書いて作業します。
作業は、Microsoft Queryか、VBAで行います。
なお、2つの表を「本記事のような条件で」比べる場合、「毎回・常にこのSQL文でOK」です。
また、今回の例については、
重複チェックをする列が、「列01~列04の4つ」で、
その「すべての列を同時に」、重複しているかどうかを調べます。(連番列以外の列です。)
以下のSQL文ですと、「ON ~ AND ~ AND ~ ・・・」という部分(4行分)が、
重複チェックしている部分です。(「AND」は「かつ」という意味です。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
' ' SELECT B表.* FROM (SELECT B表.連番 FROM A表 LEFT JOIN B表 ON (A表.列01 = B表.列01) AND (A表.列02 = B表.列02) AND (A表.列03 = B表.列03) AND (A表.列04 = B表.列04) WHERE B表.連番 Is Not Null) AS C表 RIGHT JOIN B表 ON C表.連番 = B表.連番 WHERE C表.連番 Is Null; ' ' |
なお、重複を比較する列の名前は、A表とB表のあいだでは、「全く同じでなくてもOK」です。
列名が異なっていても、列同士の「データ型」と、格納されている値そのものが正常なら大丈夫です。
その場合は、お互い「列01」のところで、異なる列名を書き合います。それでOKです。
逆に、誰かがデータを変にいじってしまい、『 内容がメチャクチャになってしまっている 』ような状況ですと、もし列名が同じであっても・・・、
「エラーになって止まってしまう」か、
「とりあえず動くけど、でも絶対に重複はヒットしない」、
・・・という状況になってしまいます。
(Excelは初期状態では、「入力データのデータ型をそろえたりチェックしたりする機能がまったくといっていいほど働いていない」ので、結果、何でもできてしまい、「データや数式をメチャメチャにし放題」なので、注意が必要です。そこが「Excelはあまりデータ蓄積には向かない」と言われる一番の理由だと思います。ただ、そこさえちゃんと気を付けて、「他の人の自由にさせない」仕組みを追加すれば、Excelでもなんとかシステムめいたものが作れると思います。もちろん、SQLも使えます。)
以上は、定型的な作業なので、
最初のうちは「SELECT」や「FROM」「WHERE」などの意味がわからなくてもOKですが、
でも必ず、少しずつでも意味を学び、SQL文について少しずつでもいいので、
理解を深めていってほしいと思います。
そうするとExcelのフィルタ機能よりもさらに細かい動きをさせることができますし、
何といっても、
「VBAプログラムよりも短い文で」書けますし、
「ワークシート関数よりも分かりやすく複数の条件が書けます」から、
結果的に
「無駄で、本来書かなくていいVBAやワークシート関数を書いたり」、
「意味のわかりにくい修正しにくいVBAやワークシート関数を書く」、
というムダが減ります。
システム業者もVBAよりもSQLを使うので、メンテはもちろん、その他いろんな方面、例えば「高機能化のための外注時」にもコストが抑えられます。
特に、VBAやワークシート関数は「セルの位置」でなんでもやるので、A表やB表の列が増えたり行が増えたりするとそのたびに「何がどうなっているかを考え直して」プログラムをムダに書き換えないといけません。しかもループも使うことも多いのでわかりづらい&間違えやすいです。特に初心者には。=メンテもしにくい、ということでもあります。
でも、SQLを使うと、列名でプログラムが書けますから目的の列のデータがどのセルにあろうが場所が変わろうが そんなことは関係が無く、考える必要がありません。行についても「増えることが前提なので考えなくていい」ですし、ループなんて使わないもんですから、なので(基礎さえわかれば)VBAよりは意味がわかりやすいです。
なので、内容を書き換えるにしても無駄なVBAや無駄なワークシート関数よりは「書き換えやすい」「書き換える箇所が少ない」というメリットがあります。
「一度作ったものを、VBAやワークシート関数よりも "使いまわし・再利用がしやすい" というメリットがある、」=「時間をムダにしないというメリットがある」ということになります。
はっきり言って、SQLを知らずに(使わずに)VBAのループ処理ばかり自慢する人(ループ処理しか書かない人)は「愚かで即戦力にはなりません」。SQLを知ってて、でも状況によってあえてSQLを使わない人は「即戦力になる」と思います。
僕はSQLは得意ではないですが、「何がどうできるか?くらいのおおよそのこと」は知っていますので、ExcelVBAができるだけの人と、SQLもVBA知ってて効率化してくれる人とだったら、後者の方を採用しますし、お給料にも差をつけます。(もちろん、SQLを使って効率化が本当にできれば、ですが。)
もちろん、SQLも万能ではないですからVBAでのループ処理ももちろん「大切なもの」ですが、でも「SQLをまったく知らない」と、すぐに、「無駄・かつ・メンテしにくいループが増える」=無駄な時間コストや金額コストが増える、ということになるので、罪であることは確かなのです。
特に「経営者目線」、「独立する人間目線」、では。
※補足01:
コードの2行目~9行目(最初の FROMの次から、「AS C表」 の前まで)のカッコの中が
「副問い合わせ(サブクエリとも言います)」と呼ばれる部分となります。
このカッコの中で「重複データの抽出」をしています。
カッコの外で、「その重複以外のデータの抽出」をしています。
※補足02:
最終的には、上記のようなSQL文を書きますが、
重複チェックしたい列が増えるごとに、
「AND (A表.列04 = B表.列04)」の行 以降を、
AND (A表.列05 = B表.列05)
AND (A表.列06 = B表.列06)
AND (A表.列07 = B表.列07)・・・
という感じで増やしていきます。
逆に、「列03と列05だけの同時重複を調べるだけでいい・・・、という場合は、
ON (A表.列03 = B表.列03)
AND (A表.列05 = B表.列05)
という形に減らします。
例えば「氏名の列と市区町村の列だけの同時重複を調べるだけでいい・・・」という場合は、
ON (A表.氏名 = B表.氏名)
AND (A表.市区町村 = B表.市区町村)
という書き方になります。
なお、もし B表側で、本来「市区町村」となるはずの列が「市」という列名になってしまっていたら、
ON (A表.氏名 = B表.氏名)
AND (A表.市区町村 = B表.市)
という書き方になります。
各行の先頭にスペースは必ず入れておきます。
(あとで自動的に適量にカットされますので。)
SELECT、FROM、LIGHT、REFT、その他、などを「句」と呼ぶんですが、その前後は「半角スペースならどれだけ入っていてもOKです。ただし、「全角スペース」が入るとエラーになりますから、絶対に全角スペースは使わないでください。
特に、Webからのサンプルのコピペの場合、なんらかの理由で全角スペースが混ざることがあるので本当に注意してください。命令文が完璧でもエラーが出続けてしまいます。
※補足03:
SQL文の作成に関しては、
テキストエディタやWordなどを利用して、A表、B表、の部分を置換し、
そのあと、列01~列04 も必要に応じて置換します。
そうすれば、作業がラクになるかと思います。
C表は置換しません。
(※VBAで使う場合でも、Microsoft Query、
あるいはAccessその他で使う場合でも同じです。)
置換では駄目な場合は、
必要に応じて、表(シート側)のほうの列名を手修正で書き換えるか、
SQL文のほうの 列01~列04 の部分を、
現状に合致するように手修正で書き換えます。
なお、B表とA表を逆にして調べたかったら・・・・、
例えば「B表側ではなく、A表側の行をピックアップや削除」
ということをしたかったら、単純に、逆に置換すればいいだけです。
ただ、その場合、両方の表の間で列名が一部異なるような場合は、
それをその状況に合致するように(列名を)手修正する必要があります。
★ 2つのテーブルの間での重複チェック
4つのフィールドの例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
' ' SELECT T99_社員マスタ.連番, t99_社員マスタ002.連番 FROM T99_社員マスタ INNER JOIN t99_社員マスタ002 ON (T99_社員マスタ.社員番号 = t99_社員マスタ002.社員番号) AND (T99_社員マスタ.社員名 = t99_社員マスタ002.社員名) AND (T99_社員マスタ.退社日付 = t99_社員マスタ002.退社日付) AND (T99_社員マスタ.入室ID = t99_社員マスタ002.入室ID); 結果: T99_社員マスタ.連番 t99_社員マスタ002.連番 1 4 3 2 ' ' |
★ 2つのテーブルの間での不一致データのチェック(副問い合わせの利用)
※元となるテーブルがT99_社員マスタ
重複データを消したいテーブルがt99_社員マスタ002
カットしたい連番だけを選択して表示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
' ' SELECT t99_社員マスタ002.連番 FROM (SELECT t99_社員マスタ002.連番 FROM T99_社員マスタ LEFT JOIN t99_社員マスタ002 ON (T99_社員マスタ.社員番号 = t99_社員マスタ002.社員番号) AND (T99_社員マスタ.社員名 = t99_社員マスタ002.社員名) AND (T99_社員マスタ.退社日付 = t99_社員マスタ002.退社日付) AND (T99_社員マスタ.入室ID = t99_社員マスタ002.入室ID) WHERE t99_社員マスタ002.連番 Is Not Null) AS C表 RIGHT JOIN t99_社員マスタ002 ON C表.連番 = t99_社員マスタ002.連番 WHERE C表.連番 Is Null; 結果: 連番 3 1 ' ' |
カットしたい連番も、氏名その他すべてをも選択して表示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
' ' SELECT t99_社員マスタ002.* FROM (SELECT t99_社員マスタ002.連番 FROM T99_社員マスタ LEFT JOIN t99_社員マスタ002 ON (T99_社員マスタ.社員番号 = t99_社員マスタ002.社員番号) AND (T99_社員マスタ.社員名 = t99_社員マスタ002.社員名) AND (T99_社員マスタ.退社日付 = t99_社員マスタ002.退社日付) AND (T99_社員マスタ.入室ID = t99_社員マスタ002.入室ID) WHERE t99_社員マスタ002.連番 Is Not Null) AS C表 RIGHT JOIN t99_社員マスタ002 ON C表.連番 = t99_社員マスタ002.連番 WHERE C表.連番 Is Null; 結果: 連番 社員番号 社員名 退社日付 入室ID 3 6 田中 正志 2019/05/17 9 1 5 並木 佳野 2019/09/19 2 ' ' |
===========================================
★ 参考操作
※ すみません!ミスです!この「参考操作」の項のところだけ、「削除分」を「重複分」に読み替えてください。
(SQL内容も。)
(A)まず「t99_社員マスタ002削除分」クエリを作成
1 2 3 4 5 6 7 8 9 10 11 12 |
' ' SELECT t99_社員マスタ002.連番 FROM T99_社員マスタ LEFT JOIN t99_社員マスタ002 ON (T99_社員マスタ.社員番号 = t99_社員マスタ002.社員番号) AND (T99_社員マスタ.社員名 = t99_社員マスタ002.社員名) AND (T99_社員マスタ.退社日付 = t99_社員マスタ002.退社日付) AND (T99_社員マスタ.入室ID = t99_社員マスタ002.入室ID) WHERE t99_社員マスタ002.連番 Is Not Null; ' ' |
(B)その「t99_社員マスタ002削除分」クエリをもとに、不一致クエリを作成
1 2 3 4 5 6 7 8 9 |
' ' SELECT t99_社員マスタ002.* FROM t99_社員マスタ002削除分 RIGHT JOIN t99_社員マスタ002 ON t99_社員マスタ002削除分.連番 = t99_社員マスタ002.連番 WHERE t99_社員マスタ002削除分.連番 Is Null; ' ' |
(C)上記の2つのクエリをひとつにまとめる(副問い合わせの利用。)
方法は、まず、(B)のFROM句の「t99_社員マスタ002削除分」の部分を、
(A)の「t99_社員マスタ002削除分」クエリの内容に置き換え、「AS C表」(C表)とし、
RIGHT JOIN 句 や WHERE句 の「t99_社員マスタ002削除分」と記述されたところを
「C」(C表)に書き換えます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
' ' SELECT t99_社員マスタ002.* FROM (SELECT t99_社員マスタ002.連番 FROM T99_社員マスタ LEFT JOIN t99_社員マスタ002 ON (T99_社員マスタ.社員番号 = t99_社員マスタ002.社員番号) AND (T99_社員マスタ.社員名 = t99_社員マスタ002.社員名) AND (T99_社員マスタ.退社日付 = t99_社員マスタ002.退社日付) AND (T99_社員マスタ.入室ID = t99_社員マスタ002.入室ID) WHERE t99_社員マスタ002.連番 Is Not Null) AS C表 RIGHT JOIN t99_社員マスタ002 ON C表.連番 = t99_社員マスタ002.連番 WHERE C表.連番 Is Null; ' ' |
(D) (C)で、リストアップされた内容が確認できたら、
「SELECT t99_社員マスタ002.*」の「*」を「連番」に書き換える。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
' ' SELECT t99_社員マスタ002.連番 FROM (SELECT t99_社員マスタ002.連番 FROM T99_社員マスタ LEFT JOIN t99_社員マスタ002 ON (T99_社員マスタ.社員番号 = t99_社員マスタ002.社員番号) AND (T99_社員マスタ.社員名 = t99_社員マスタ002.社員名) AND (T99_社員マスタ.退社日付 = t99_社員マスタ002.退社日付) AND (T99_社員マスタ.入室ID = t99_社員マスタ002.入室ID) WHERE t99_社員マスタ002.連番 Is Not Null) AS C表 RIGHT JOIN t99_社員マスタ002 ON C表.連番 = t99_社員マスタ002.連番 WHERE C表.連番 Is Null; ' ' |
===========================================
★ ExcelのMicrosoft Query や、QueryTableオブジェクト+VBA(ODBC等)の場合
※読み込み先のファイルがExcelファイルの場合、テーブル名には「&」をつけて、[ ](あるいはバックスラッシュ)で囲む必要があります。
仮想表の「C表」にもそれをおこないます。
なお、読み込み先のファイルが、『 テキストファイルやAccessファイル、SQL Server など 』でしたら、Microsoft Query やQueryTableオブジェクトでの利用であっても、そのSQL 文のテーブル名には、その処置は要りません。
(この記事の最初にご紹介したようなSQL 文となります。)
参考:『「VBAプログラム」からも、「MicrosoftQueryの画面」からも操作が可能となる、そのための「VBAからのSQLの書き方」や「前提条件」など(概要説明のみ)』
(01)Microsoft Queryの「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 |
' ' SELECT [B表$].* FROM (SELECT [B表$].連番 FROM [A表$] LEFT JOIN [B表$] ON ([A表$].列01 = [B表$].列01) AND ([A表$].列02 = [B表$].列02) AND ([A表$].列03 = [B表$].列03) AND ([A表$].列04 = [B表$].列04) WHERE [B表$].連番 Is Not Null) AS [C表$] RIGHT JOIN [B表$] ON [C表$].連番 = [B表$].連番 WHERE [C表$].連番 Is Null; 例: SELECT [t99_社員マスタ002$].* FROM (SELECT [t99_社員マスタ002$].連番 FROM [T99_社員マスタ$] LEFT JOIN [t99_社員マスタ002$] ON ([T99_社員マスタ$].社員番号 = [t99_社員マスタ002$].社員番号) AND ([T99_社員マスタ$].社員名 = [t99_社員マスタ002$].社員名) AND ([T99_社員マスタ$].退社日付 = [t99_社員マスタ002$].退社日付) AND ([T99_社員マスタ$].入室ID = [t99_社員マスタ002$].入室ID) WHERE [t99_社員マスタ002$].連番 Is Not Null) AS [C表$] RIGHT JOIN [t99_社員マスタ002$] ON [C表$].連番 = [t99_社員マスタ002$].連番 WHERE [C表$].連番 Is Null; ' ' |
(02)QueryTableオブジェクト+VBA(ODBC等)の場合(変数利用:Arrey)
比較したい列の数が増える場合、条件の「AND ([A表$].列××× = [B表$].列×××)"」の行が増える(増やす)ような格好となります。
その際は、
s_SQL02 = s_SQL02 & " ・・・・・"
s_SQL03 = s_SQL03 & " ・・・・・"
s_SQL04 = s_SQL04 & " ・・・・・"
の、ところで、それぞれの変数に均等に割り振って(差し込んで)いきます。
" ・・・・・" の中に書く 「AND」の前は「半角の」スペースならいくつ入っていてもOKです。「全角」のスペースはエラーになるので絶対に書かないでください。
なお、逆に条件が少ない時は
s_SQL02 = s_SQL02 & " ・・・・・"
s_SQL03 = s_SQL03 & ""
s_SQL04 = s_SQL04 & ""
といった感じで、どれかの変数は "" にしてしまってもOKです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
' ' s_SQL01 = s_SQL01 & "SELECT [B表$].連番" s_SQL01 = s_SQL01 & " FROM (SELECT [B表$].連番" s_SQL01 = s_SQL01 & " FROM [A表$]" s_SQL01 = s_SQL01 & " LEFT JOIN [B表$]" s_SQL02 = s_SQL02 & " ON ([A表$].列01 = [B表$].列01)" s_SQL02 = s_SQL02 & " AND ([A表$].列02 = [B表$].列02)" s_SQL03 = s_SQL03 & " AND ([A表$].列03 = [B表$].列03)" s_SQL04 = s_SQL04 & " AND ([A表$].列04 = [B表$].列04)" s_SQL05 = s_SQL05 & " WHERE [B表$].連番 Is Not Null) AS [C表$]" s_SQL05 = s_SQL05 & " RIGHT JOIN [B表$]" s_SQL05 = s_SQL05 & " ON [C表$].連番 = [B表$].連番" s_SQL05 = s_SQL05 & " WHERE [C表$].連番 Is Null;" ' ' |
===========================================
===========================================
===========================================
例:他ファイルから吸い込み。
「'アクティブシートに結果を表示」のところで、直接、他のファイル(フルパスとパス)を指定しています。(「;DBQ=」のところでフルパスを、「;DefaultDir=」のところでパスを指定しています。)
※実行する前に、必ず前回の結果を列丸ごと、削除してください。
でないと実行する度に結果の表が増えていったり、出力する列数が少ないと、前回の結果と横に合体してしまって「何も変化してない」と勘違いしてしまうことがあるので。
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 |
' ' Sub Test01() Dim s_SQL01 As String Dim s_SQL02 As String Dim s_SQL03 As String Dim s_SQL04 As String Dim s_SQL05 As String s_SQL01 = s_SQL01 & "SELECT [t99_社員マスタ002$].*" s_SQL01 = s_SQL01 & " FROM (SELECT [t99_社員マスタ002$].連番" s_SQL01 = s_SQL01 & " FROM [T99_社員マスタ$]" s_SQL01 = s_SQL01 & " LEFT JOIN [t99_社員マスタ002$]" s_SQL02 = s_SQL02 & " ON ([T99_社員マスタ$].社員番号 = [t99_社員マスタ002$].社員番号)" s_SQL02 = s_SQL02 & " AND ([T99_社員マスタ$].社員名 = [t99_社員マスタ002$].社員名)" s_SQL03 = s_SQL03 & " AND ([T99_社員マスタ$].退社日付 = [t99_社員マスタ002$].退社日付)" s_SQL04 = s_SQL04 & " AND ([T99_社員マスタ$].入室ID = [t99_社員マスタ002$].入室ID)" s_SQL05 = s_SQL05 & " WHERE [t99_社員マスタ002$].連番 Is Not Null) AS [C表$]" s_SQL05 = s_SQL05 & " RIGHT JOIN [t99_社員マスタ002$]" s_SQL05 = s_SQL05 & " ON [C表$].連番 = [t99_社員マスタ002$].連番" s_SQL05 = s_SQL05 & " WHERE [C表$].連番 Is Null;" 'アクティブシートに結果を表示 With ActiveSheet.QueryTables.Add(Connection:= _ "ODBC;DSN=Excel Files;DBQ=D:\1\重複チェックtest01.xls;DefaultDir=D:\1;DriverId=790;MaxBufferSize=2048;PageTimeout=5;" _ , Destination:=Range("A1")) .CommandText = Array(s_SQL01, s_SQL02, s_SQL03, s_SQL04, s_SQL05) .Name = "Excel Files からのクエリ" .FieldNames = True .RowNumbers = False .FillAdjacentFormulas = False .PreserveFormatting = True .RefreshOnFileOpen = False .BackgroundQuery = True .RefreshStyle = xlInsertDeleteCells .SavePassword = True .SaveData = True .AdjustColumnWidth = True .RefreshPeriod = 0 .PreserveColumnInfo = True .Refresh BackgroundQuery:=False ' .Refresh End With End Sub ' ' |
===========================================
===========================================
===========================================
例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 |
' ' Sub Test02() Dim s_SQL01 As String Dim s_SQL02 As String Dim s_SQL03 As String Dim s_SQL04 As String Dim s_SQL05 As String Dim s_FilePath As String Dim s_FileNm As String Dim s_FileFullNm As String ' '他のファイルを指定 ' s_FilePath = "D:\1" ' s_FileNm = "重複チェックtest01.xls" ' s_FileFullNm = s_FilePath & "\" & s_FileNm '自ファイルを指定 s_FilePath = ThisWorkbook.Path s_FileNm = ThisWorkbook.Name s_FileFullNm = s_FilePath & "\" & s_FileNm s_SQL01 = s_SQL01 & "SELECT [t99_社員マスタ002$].*" s_SQL01 = s_SQL01 & " FROM (SELECT [t99_社員マスタ002$].連番" s_SQL01 = s_SQL01 & " FROM [T99_社員マスタ$]" s_SQL01 = s_SQL01 & " LEFT JOIN [t99_社員マスタ002$]" s_SQL02 = s_SQL02 & " ON ([T99_社員マスタ$].社員番号 = [t99_社員マスタ002$].社員番号)" s_SQL02 = s_SQL02 & " AND ([T99_社員マスタ$].社員名 = [t99_社員マスタ002$].社員名)" s_SQL03 = s_SQL03 & " AND ([T99_社員マスタ$].退社日付 = [t99_社員マスタ002$].退社日付)" s_SQL04 = s_SQL04 & " AND ([T99_社員マスタ$].入室ID = [t99_社員マスタ002$].入室ID)" s_SQL05 = s_SQL05 & " WHERE [t99_社員マスタ002$].連番 Is Not Null) AS [C表$]" s_SQL05 = s_SQL05 & " RIGHT JOIN [t99_社員マスタ002$]" s_SQL05 = s_SQL05 & " ON [C表$].連番 = [t99_社員マスタ002$].連番" s_SQL05 = s_SQL05 & " WHERE [C表$].連番 Is Null;" ' s_SQL01 = s_SQL01 & "SELECT [T99_社員マスタ$].*" ' s_SQL01 = s_SQL01 & " FROM (SELECT [T99_社員マスタ$].連番" ' s_SQL01 = s_SQL01 & " FROM [t99_社員マスタ002$]" ' s_SQL01 = s_SQL01 & " LEFT JOIN [T99_社員マスタ$]" ' s_SQL02 = s_SQL02 & " ON ([t99_社員マスタ002$].社員番号 = [T99_社員マスタ$].社員番号)" ' s_SQL02 = s_SQL02 & " AND ([t99_社員マスタ002$].社員名 = [T99_社員マスタ$].社員名)" ' s_SQL03 = s_SQL03 & " AND ([t99_社員マスタ002$].退社日付 = [T99_社員マスタ$].退社日付)" ' s_SQL04 = s_SQL04 & " AND ([t99_社員マスタ002$].入室ID = [T99_社員マスタ$].入室ID)" ' s_SQL05 = s_SQL05 & " WHERE [T99_社員マスタ$].連番 Is Not Null) AS [C表$]" ' s_SQL05 = s_SQL05 & " RIGHT JOIN [T99_社員マスタ$]" ' s_SQL05 = s_SQL05 & " ON [C表$].連番 = [T99_社員マスタ$].連番" ' s_SQL05 = s_SQL05 & " WHERE [C表$].連番 Is Null;" With ActiveSheet.QueryTables.Add(Connection:= _ "ODBC;DSN=Excel Files;DBQ=" & s_FileFullNm & ";DefaultDir=" & s_FilePath & ";DriverId=790;MaxBufferSize=2048;PageTimeout=5;" _ , Destination:=Range("A1")) .CommandText = Array(s_SQL01, s_SQL02, s_SQL03, s_SQL04, s_SQL05) .Name = "Excel Files からのクエリ" .FieldNames = True .RowNumbers = False .FillAdjacentFormulas = False .PreserveFormatting = True .RefreshOnFileOpen = False .BackgroundQuery = True .RefreshStyle = xlInsertDeleteCells .SavePassword = True .SaveData = True .AdjustColumnWidth = True .RefreshPeriod = 0 .PreserveColumnInfo = True .Refresh BackgroundQuery:=False ' .Refresh End With End Sub ' ' |
===========================================
===========================================
===========================================
例03:SQLで吸い込む動作を関数化して、自ファイルに。
後述の(イ)や(ロ)の部分だけのように書いていけばOKとなります。
データの抽出だけなら、それだけのコードで済みます。
※実行する前に、前回の結果は「削除なくても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 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 |
' ' Sub Macro4() ' Dim s_SQL01 As String Dim s_SQL02 As String Dim s_SQL03 As String Dim s_SQL04 As String Dim s_SQL05 As String Dim v_Sql01 As Variant Dim s_FilePath As String Dim s_FileNm As String Dim s_FileFullNm As String Dim s_ShtNm01 As String ' '他のファイルを指定 ' s_FilePath = "D:\1" ' s_FileNm = "重複チェックtest01.xls" ' s_FileFullNm = s_FilePath & "\" & s_FileNm '自ファイルを指定 s_FilePath = ThisWorkbook.Path s_FileNm = ThisWorkbook.Name s_FileFullNm = s_FilePath & "\" & s_FileNm '吸い込むシートをどれにするかの設定 ' s_ShtNm01 = ActiveWorkbook.Worksheets("Sheet3") s_ShtNm01 = ActiveSheet.Name s_SQL01 = s_SQL01 & "SELECT [t99_社員マスタ002$].*" s_SQL01 = s_SQL01 & " FROM (SELECT [t99_社員マスタ002$].連番" s_SQL01 = s_SQL01 & " FROM [T99_社員マスタ$]" s_SQL01 = s_SQL01 & " LEFT JOIN [t99_社員マスタ002$]" s_SQL02 = s_SQL02 & " ON ([T99_社員マスタ$].社員番号 = [t99_社員マスタ002$].社員番号)" s_SQL02 = s_SQL02 & " AND ([T99_社員マスタ$].社員名 = [t99_社員マスタ002$].社員名)" s_SQL03 = s_SQL03 & " AND ([T99_社員マスタ$].退社日付 = [t99_社員マスタ002$].退社日付)" s_SQL04 = s_SQL04 & " AND ([T99_社員マスタ$].入室ID = [t99_社員マスタ002$].入室ID)" s_SQL05 = s_SQL05 & " WHERE [t99_社員マスタ002$].連番 Is Not Null) AS [C表$]" s_SQL05 = s_SQL05 & " RIGHT JOIN [t99_社員マスタ002$]" s_SQL05 = s_SQL05 & " ON [C表$].連番 = [t99_社員マスタ002$].連番" s_SQL05 = s_SQL05 & " WHERE [C表$].連番 Is Null;" ' s_SQL01 = s_SQL01 & "SELECT [T99_社員マスタ$].*" ' s_SQL01 = s_SQL01 & " FROM (SELECT [T99_社員マスタ$].連番" ' s_SQL01 = s_SQL01 & " FROM [t99_社員マスタ002$]" ' s_SQL01 = s_SQL01 & " LEFT JOIN [T99_社員マスタ$]" ' s_SQL02 = s_SQL02 & " ON ([t99_社員マスタ002$].社員番号 = [T99_社員マスタ$].社員番号)" ' s_SQL02 = s_SQL02 & " AND ([t99_社員マスタ002$].社員名 = [T99_社員マスタ$].社員名)" ' s_SQL03 = s_SQL03 & " AND ([t99_社員マスタ002$].退社日付 = [T99_社員マスタ$].退社日付)" ' s_SQL04 = s_SQL04 & " AND ([t99_社員マスタ002$].入室ID = [T99_社員マスタ$].入室ID)" ' s_SQL05 = s_SQL05 & " WHERE [T99_社員マスタ$].連番 Is Not Null) AS [C表$]" ' s_SQL05 = s_SQL05 & " RIGHT JOIN [T99_社員マスタ$]" ' s_SQL05 = s_SQL05 & " ON [C表$].連番 = [T99_社員マスタ$].連番" ' s_SQL05 = s_SQL05 & " WHERE [C表$].連番 Is Null;" v_Sql01 = Array(s_SQL01, s_SQL02, s_SQL03, s_SQL04, s_SQL05) Call vrtMakeMsqOwnFileTest02(s_FileFullNm, s_FilePath, s_ShtNm01, v_Sql01) End Sub '################################################################################################################################################################### '自ファイルの指定したシートに他ファイルのデータをMicrosoftQueryに読み込む関数 '(A1セルを起点に吸い込み) ' 'strSrcFullPath01 :読み込みたいファイルのフルパスを指定します。一応xlsmやxlsx。xlsの場合は"DriverId=1046;"を"DriverId=790;"に変えたほうがいいかもしれません。 'strSrcFdPath01 :読み込みたいファイルのフォルダパスを指定します。(ファイル名を除いたもの) 'strImpShtNm01 :吸い込みたい自ファイルのシートの名前を指定します。 'vrtSql01 :SQL文を指定します。 ' 句ごとか、一定の文字数(300文字ごとくらい)ごとの ' 配列として扱います。 ' SQLの実行の段階で、MicrosoftQuery(QueryTableオブジェクト)の ' CommandTextプロパティにこの変数に代入したSQL文を渡すのですが、 ' それが「Variant型」の「配列」であるため、 ' ここでもVariant型を使います。 ' '################################################################################################################################################################### Sub vrtMakeMsqOwnFileTest02(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 Dim objPrms01 As Parameters '*********************************************************************************************************************************** '覗きに行くデータへの接続をするときの、接続文字列の設定。 '接続文字列が横に長くて見にくくなってしまうので、見やすく扱いやすく(書き換えやすく)します。 'いじるのは「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")) Qt_MeQtbl01.CommandText = vrtSQL01 'SQL文を設定 Qt_MeQtbl01.Refresh 'SQL文の実行と反映 Exit Sub '何もない状態から作ったので、プログラム自体をここで終わらせます。 Else 'もしすでに、指定したシートにMicrosoftQueryの結果の表が 'あったら何もしないで次へ。 End If '******************************************************************************* '既にMicrosoftQueryの表があったら、その SQL内容だけを書き換えて反映させる処理。 '******************************************************************************* 'もし、既存のMicrosoftQueryの表にパラメータが設定されていたらそれを削除。 'パラメータがセルに設定されていた場合、新しいクエリがそのセルにかぶると '動作がおかしくなることがあるため。 Set objPrms01 = Ws_MeSht01.QueryTables(1).Parameters If 1 <= objPrms01.Count Then objPrms01.Delete '実際のSQL文の書き換えと実行 Ws_MeSht01.QueryTables(1).CommandText = vrtSQL01 'SQL文を設定(書き換え) Ws_MeSht01.QueryTables(1).Refresh BackgroundQuery:=False 'SQLの実行と表示 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 |
' ' Sub Macro4() ' Dim s_SQL01 As String Dim s_SQL02 As String Dim s_SQL03 As String Dim s_SQL04 As String Dim s_SQL05 As String Dim v_Sql01 As Variant Dim s_FilePath As String Dim s_FileNm As String Dim s_FileFullNm As String Dim s_ShtNm01 As String '自ファイルを指定 s_FilePath = ThisWorkbook.Path s_FileNm = ThisWorkbook.Name s_FileFullNm = s_FilePath & "\" & s_FileNm '吸い込むシートをどれにするかの設定 ' s_ShtNm01 = ActiveWorkbook.Worksheets("Sheet3") s_ShtNm01 = ActiveSheet.Name s_SQL01 = s_SQL01 & "SELECT [t99_社員マスタ002$].*" s_SQL01 = s_SQL01 & " FROM (SELECT [t99_社員マスタ002$].連番" s_SQL01 = s_SQL01 & " FROM [T99_社員マスタ$]" s_SQL01 = s_SQL01 & " LEFT JOIN [t99_社員マスタ002$]" s_SQL02 = s_SQL02 & " ON ([T99_社員マスタ$].社員番号 = [t99_社員マスタ002$].社員番号)" s_SQL02 = s_SQL02 & " AND ([T99_社員マスタ$].社員名 = [t99_社員マスタ002$].社員名)" s_SQL03 = s_SQL03 & " AND ([T99_社員マスタ$].退社日付 = [t99_社員マスタ002$].退社日付)" s_SQL04 = s_SQL04 & " AND ([T99_社員マスタ$].入室ID = [t99_社員マスタ002$].入室ID)" s_SQL05 = s_SQL05 & " WHERE [t99_社員マスタ002$].連番 Is Not Null) AS [C表$]" s_SQL05 = s_SQL05 & " RIGHT JOIN [t99_社員マスタ002$]" s_SQL05 = s_SQL05 & " ON [C表$].連番 = [t99_社員マスタ002$].連番" s_SQL05 = s_SQL05 & " WHERE [C表$].連番 Is Null;" v_Sql01 = Array(s_SQL01, s_SQL02, s_SQL03, s_SQL04, s_SQL05) Call vrtMakeMsqOwnFileTest02(s_FileFullNm, s_FilePath, s_ShtNm01, v_Sql01) 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 |
' ' Sub Macro4() ' Dim s_SQL01 As String Dim s_SQL02 As String Dim s_SQL03 As String Dim s_SQL04 As String Dim s_SQL05 As String Dim v_Sql01 As Variant Dim s_FilePath As String Dim s_FileNm As String Dim s_FileFullNm As String Dim s_ShtNm01 As String '他のファイルを指定 s_FilePath = "D:\1" s_FileNm = "重複チェックtest01.xls" s_FileFullNm = s_FilePath & "\" & s_FileNm '吸い込むシートをどれにするかの設定 ' s_ShtNm01 = ActiveWorkbook.Worksheets("Sheet3") s_ShtNm01 = ActiveSheet.Name s_SQL01 = s_SQL01 & "SELECT [T99_社員マスタ$].*" s_SQL01 = s_SQL01 & " FROM (SELECT [T99_社員マスタ$].連番" s_SQL01 = s_SQL01 & " FROM [t99_社員マスタ002$]" s_SQL01 = s_SQL01 & " LEFT JOIN [T99_社員マスタ$]" s_SQL02 = s_SQL02 & " ON ([t99_社員マスタ002$].社員番号 = [T99_社員マスタ$].社員番号)" s_SQL02 = s_SQL02 & " AND ([t99_社員マスタ002$].社員名 = [T99_社員マスタ$].社員名)" s_SQL03 = s_SQL03 & " AND ([t99_社員マスタ002$].退社日付 = [T99_社員マスタ$].退社日付)" s_SQL04 = s_SQL04 & " AND ([t99_社員マスタ002$].入室ID = [T99_社員マスタ$].入室ID)" s_SQL05 = s_SQL05 & " WHERE [T99_社員マスタ$].連番 Is Not Null) AS [C表$]" s_SQL05 = s_SQL05 & " RIGHT JOIN [T99_社員マスタ$]" s_SQL05 = s_SQL05 & " ON [C表$].連番 = [T99_社員マスタ$].連番" s_SQL05 = s_SQL05 & " WHERE [C表$].連番 Is Null;" v_Sql01 = Array(s_SQL01, s_SQL02, s_SQL03, s_SQL04, s_SQL05) Call vrtMakeMsqOwnFileTest02(s_FileFullNm, s_FilePath, s_ShtNm01, v_Sql01) End Sub ' ' |