● VBAプログラムのコメントは、だらだらと沢山書きましょう。特に売るソフトを作るわけでもない私たち素人はそうしたほうがいいです。なんでもかんでも「プロ」の真似をすると、引継ぎのときに「ハマる」ことになります。「VBAプログラムのコメントはほどほどに。長々と書くのはやめましょう」は絶対に信用しないように!
※間違ってない重要なことなのでご自分でも考えてください。
※メモ書きなので、自分でも意味不明な箇所も多いです。ごめんなさい。
よく「VBAプログラムのコメントはほどほどに。長々と書くのはやめましょう」などと言われます。
でもそれは「売るソフトを作る人・会社」の場合だけです。
そもそも、コメントなんて、ちゃんとした人なら一瞬で「すべてのコメントを一発ではずすプログラム」を作って、「無かったもの」にできます。
必要なコメントだけを残すのだって、一瞬で、できます。
「コメント(特に設計変更理由なども含む)」は、私たち素人には引継ぎ後の「命綱」になることも多いです。(外部に委託する場合、作り変えしてもらう場合、なども命綱になります。料金の低下にも結び付きます。)
絶対に、「VBAプログラムのコメントはほどほどに。長々と書くのはやめましょう」などということには騙されないように、設計に関することや社内体制・ツルの一声・その他、すべての事柄についてコメントを書きまくりましょう。(あくまで販売しない・社内で使うだけのエンドユーザーコンピューティングのプログラムの場合、特にプログラム初心者や中級者に引き継がねばならないケースがいつの世代も想定される場合、等々、ですが。)
逆に、「設計に関することや社内体制・ツルの一声・その他、すべての事柄について」・・・、いちいち、それらについてのコメントを何か別のファイルや別紙などに「分けて」残したりすると、部署の刷新やパソコンの入れ替え、事務所内の模様替え、OSの再インストール、その他諸々のとき、そういった「別のファイルや紙など」を誤って捨ててしまうことが非常に多いです。
例えば、「メールのパスワードやサーバ名、プロバイダのパスワードやルーターの変更したパスワード」などなど・・・、ちゃんと現行の内容を「全て」残せている人がどれだけいますか?いま「絶対OK」と即答できる人、どれだけいますでしょうか?
現実にはほとんどいません。
「メールのパスワードやサーバ名?プロバイダのパスワード?ルーターの変更したパスワード?そんなのどっかいっちゃった!」という人・会社様がほとんどです。
ちなみに、ちゃんと「メールのパスワードやサーバ名?プロバイダの設定など」、こういったものをしっかり「全て」残せている方は「1割以下」です。0.5割以下かもしれません。僕はちゃんと「全部」残している人には出会ったことがありません。
「コメント(特に設計変更理由なども含む)」も、プログラムと分けて別ファイルや別紙に書いて残してしまうと、そうなります。
そして、引継ぎのあとに、「なんでこういう風にしたのか」が分からないまま、立ち尽くすことになってしまいます。
でも、プログラム内に書いておけば、「どんだけ引継ぎしても残ります。」
「フォルダ作って別ファイルに・・・」、なんてことも絶対にしたらいけません。そんなことをするから、それがそもそもの間違いのもとになります。
そんなことをすれば、どこかの世代で、「面倒だから」とそのコメントや設計変更書は消えていく羽目になります。プログラム内に残しておくのが一番管理もしやすいし効率もいいのです。
そもそも、そんなもの(メールやプロバイダやレンタルサーバなどの設定書)ごときすらが、ちゃんと管理できない人が、別の場所に分けてしまった「コメントや設計変更に関する資料、環境や社内体制の変更と共に書き換えたプログラムの内容や関連事項、その他の資料」が、管理できるわけがないじゃないですか。
最初から100%、無くすに決まっているんです。分けちゃった時点で。
火を見るよりも明らかとはこのことなのです。
だから、「VBAプログラム内に直接書きまくって残しましょう」ということを心底、おすすめします。
例えば、「ここを直したら、関連個所のあそことあそことあそこも直す・見直す」ということも書いておくと、もしなんかあったときに、修正がメチャクチャ・ラクになります。
「図が無いとわかりづらい」と言う人も居ますが、そんなのは「慣れ」です。
図などなくても長い説明の文章があればわかります。箇条書きに色々と書けばそれでもずいぶんとわかりやすくなります。(それにもともと、全部が全部、何度も見返すものでもないですし。)
図なんかなくなって、長い説明の文章があれば、その文章をもとに図式化して、数十分以内に解決できますが、重要事項(書き換え理由その他)が紛失されれば、1日や2日で済まない場合だって少なくありません。それにどうしても図が欲しかったら、Excelのセルを利用して図式化し、それをテキスト化するフリーウェアを使えばOKです。
図をとるか、1日や2日、下手したら一週間を無駄にすることを取るか、と聞かれれば、図なんかどうでもいいので、書き換えた理由や状況説明のほうが「たくさん」残っていてほしいです。
実際、僕も残っていてどれだけ助けられたことか・・・
素人には、なくてはならないものです。
別のところに分けた文書を引っ張りだしてきて、該当箇所を探すだなんて、それこそ時間の無駄・浪費でもありますし、やってられないです。プログラムのすぐそばに、全部、理由も何もかもコメントとして書いてあれば、文書探す手間もかかりません。書籍や仕様書の注釈のように番号振ってプログラムの最後にまとめて書いたっていいわけですし。(僕はそれも目が疲れて効率が悪いのでしないですけど。)
そのほか、コメントを書きまくってあると、「誰か他人が作ったプログラム」を「引き継ぐ」場合で、かつ、誰かが作ったが故に、「どうしてもエラーが出たり不具合が出たりする理由がつかめない」「エラー・不具合の解決にもともと長い年月がかかる」「エラーや動作不良の頻度がすごく少ないので原因がつかみにくい」といった場合に、別の箇所を直している最中に、たまたま、長ったらしく書いたコメントのある「単語」が目に入って、それがヒントになって解決することだってあります。これが結構大きいです。特に素人には。そして特にAccessVBAよりもExcelVBA。
他人が作ったやつ、特にExcelVBAの引継ぎは、なかなか骨の折れるものも少なくありません。
Excelは何でもできすぎるので。(Excelはデータベースソフトみたいにあれダメこれダメ最初から整理されていなくちゃダメという制限が無いので、なんでもメチャクチャにできすぎてしまい、意味の分からないぐちゃぐちゃなプログラムを改修させられることが少なくないので。プログラム自体もセル番地ベースで列名ベースじゃないのでもともと見づらい・読みづらいですしね。そういう僕もぐちゃぐちゃなプログラムを書いてしまっています。だから余計に「ExcelVBAは要注意!」、と言えます。)
自分が部分改修したことが原因でさらにエラーになることもありますし。
ExcelVBAの改修作業ではそういったことがとても多いです。
自分が気の付いたこと全部が書いてあるコメントがそこにないと、そういうエラー解決のための「気付き」は得られません。
真っ白な、そしてコードだけのプログラムを眺めさせられても、そういう気付きを、特に私たち素人は絶対に得られないのです。
「コメントは最小限にしたほうが頭良さそうにみえるでしょ?」とか「実際、バカはコメントが多い」などと「カッコつける」「人をけなす」必要なんてまるでありません。本当のこと言えば、コメントが目に移っても脳に到達させない技術(後述)が無い人のほうがバカだと思います。
バカにしたい奴にはさせておいて、自分は自分の目の前の問題を解決しましょう。
そいつが責任とってくれるわけでもないですし。
私たち素人は「プロ」じゃないんですから、また、「売るソフトを作ってるわけじゃない」んですから、コメント書きまくってもそれで全然オッケーなのです。
また、他のプログラム言語はともかく、VBAに限って言えば、VBAはF8キー押下の連続で、ステップバイステップで「1行ずつ」プログラムの実行ができます。その際は、実行する行だけ黄色にハイライトさせて(変数の中身の値も確認しながら)実行できるので、コメントなんていくら書いたって邪魔にはなりません。
コメントが書いてあって目に映っていても、目に映しているだけで脳まで到達させなければ書いてないのと同じです。(それに、そもそも、VBAはコメントは全部・緑色表示なので、緑文字は脳にまで行かせないようにして見ることが可能です。それができない人のほうがおかしいです。そんな能力すらないのかしら?と心配になります。)
また、先にも書いた通り、コメントが「うざい」と思ったらコメントを全消しする、あるいは印の付けたものだけ残す、そういうプログラムを書けば一瞬で好きなように消せます。
何度も言ってしまいますけど、「うざかったら、消しゃあいい」だけの話なんです。
(念のためバックアップを作ってからそっちを消して読めばいいんです。)
消すプログラムが作れれば一発で、数秒で終わる作業です。
VBAはVBEditorの操作もできるのでそれができるかもしれません。
また、できないにしても、モジュール単位でテキストファイルにコピペしてから、コメントだけプログラムで全消しして、また、全部もとのモジュールにコピペしなおせばOKです。
なのにそれをエラそうに「コメント書きすぎ。そんなことも分からないのか!?」とかエラそうに言う人がいますが「売るソフトじゃねえんだよ!もっというと、お前だけに読ませるために残してんじゃねえんだよ!お前なんかいつ居なくなるか分かんねえじゃねえか。そんな奴の言うこと聞いてられっか。お前が居なくなったあと、素人でもなんとか分かるようにしておく必要があるんだよ!少しだけExcelができる人に対する成長への貢献・育成の意味もあるんだよ!」ということです。
例えば、以降に挙げたサンプルプログラムのように、コメントを書きまくっても、「私たち素人」にとっては「全然オッケー」です。
これでもまだ少ないほうです。
むしろ、10行でも20行でも、自分の気づいたこと、メモ、その他、社内の状況・環境で関係すること、等々、「なぜそう書いたのか?」を、すべて、書いてしまいましょう。分けて書いたらまず間違いなく、「異動の繰り返し・社内体制の変更の繰り返し」の中で「絶対に無くす・誤って捨てる・消えていく・消されていく・・・」のがオチです。
特に、社内体制や社内事情のこと、ツルの一声のことなど、は大切です。
大事なコメントを掃除やパソコン入れ替えや部署変更・環境変化等々で誤って捨ててしまわないよう、確実に、VBAプログラム内に残してください。
●コメント残しのサンプルプログラム
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 |
' ' Option Explicit '################################################################################################## 'アクティブなシートのA1セルの値にファイル名に使えない文字が含まれているかいないかのチェック事例。 '使えない記号が含まれていればエラーメッセージが出て、イミディエイトにTrueが表示されます。 '使えない記号が含まれていなければ、エラーは出ずに、イミディエイトにFalseが表示されます。 '################################################################################################## Sub test01() Dim TestStr01 As Variant 'アクティブなシートのA1セルの値を取得 TestStr01 = ActiveWorkbook.ActiveSheet.Range("A1") 'その値を、FnameNgStrChk01()関数にて、 'ファイル名に使えない記号が混ざっていないかをチェックします。 '結果はイミディエイトウィンドウに出ます。 '使えない記号が含まれていなけエラーは出ずにFalseが表示されます。 '使えない記号が含まれていればエラーが出てTrueが表示されます。 Debug.Print FnameNgStrChk01(TestStr01) End Sub '############################################################################# 'ファイル名に使えない文字のチェック用の関数。読み込み時、書き出し時、兼用。 '指定例:Debug.Print FnameNgStrChk01("ああ[あああ") ' 「 [ 」が含まれている旨のエラーが出て、 ' True(=ヒットした!含まれてた!という意味です)が返されます。 '使えない記号が含まれていればエラーが出てTrueが返ります。 '使えない記号が含まれていなけエラーは出ずにFalseが返ります。 '############################################################################# Function FnameNgStrChk01(ByVal str01 As Variant) As Boolean Dim ChkChr01 As Variant '変数「ChkChr01」に「""」を代入して初期化 ChkChr01 = "" '● 送られてきた値(str01の値)が空だったときのチェック '(一応、それぞれのパターンを書き出してみました。) If IsNull(str01) = True Then '送られてきた値がNullだったときはFalse(何もヒットしなかったよ!という意味です)を返して 'プログラムの実行を終わる。(本プログラムはAccessにも流用できると思いますが、 'NullのチェックはAccessの場合は必須です。) FnameNgStrChk01 = False Exit Function ElseIf str01 = "" Then '送られてきた値が空文字("")だったときもFalseを返してプログラムの実行を終わる。 FnameNgStrChk01 = False Exit Function Else 'それ以外の場合、つまり、チェックにひっかからなければ次へ End If '● ファイル名に使えない文字のチェック '(ヒットしたら、ヒットした文字を変数「ChkChr01」に代入します。 ' 以降の「● 最終処理」にてエラーメッセージを出すときに、どの文字がダメなのかを ' 変数「ChkChr01」を使ってユーザーに知らせたいためです。 ' なお、以下の「\」は半角の「¥」のことです。) 'Windowsの仕様によるもの(書き出し時に特に使います。読み込み時はOSがこの文字を含んだファイル名を作らせてくれないため、そもそもそのファイルを吸い込むことはありませんから、[と]だけのチェックになります。) If InStr(str01, "\") > 0 Then ChkChr01 = "\" '送られてきた文字列に「\」が含まれていたら、ChkChr01に「\」を代入します。以下同じような意味です。 If InStr(str01, "/") > 0 Then ChkChr01 = "/" If InStr(str01, ":") > 0 Then ChkChr01 = ":" If InStr(str01, "*") > 0 Then ChkChr01 = "*" If InStr(str01, "?") > 0 Then ChkChr01 = "?" If InStr(str01, """") > 0 Then ChkChr01 = """" If InStr(str01, "<") > 0 Then ChkChr01 = "<" If InStr(str01, ">") > 0 Then ChkChr01 = ">" If InStr(str01, "|") > 0 Then ChkChr01 = "|" 'Excelの仕様によるもの(書き出し時、読み込み時、両方使います) If InStr(str01, "[") > 0 Then ChkChr01 = "[" If InStr(str01, "]") > 0 Then ChkChr01 = "]" '● 最終処理 If ChkChr01 = "" Then 'ChkChr01の値が空のままなら=何もヒットしなかったのなら、= ' =ファイル名に使えない文字が何も含まれていなければ、 'Falseだけ返して何もしない。 FnameNgStrChk01 = False Else 'ChkChr01の値が空じゃないなら=ファイル名に使えない文字が含まれていれば、 'エラーメッセージで注意喚起して、Trueを返す。 MsgBox "ファイル名チェックエラー:Excelのファイル名には使えない記号、「 " & ChkChr01 & " 」が含まれています。" FnameNgStrChk01 = True End If End Function '################################################################ 'おまけ:フルパスからファイル名だけを抜粋する関数 'str02 にフルパスを指定します。 '例:Debug.Print Trimfname01("C:\folder01\smple01.xls") '「smple01.xls」が抜粋されて返ってきます。 '################################################################ Function Trimfname01(ByVal str02 As String) As String Trimfname01 = Right(str02, Len(str02) - InStrRev(str02, "\", -1, vbBinaryCompare)) End Function '###################################################################################################### '丸角矩形と矢印を、好きな色で挿入するためのプログラムです。 ' Call MakeRoundSquareSet01(255,0,0,1) といった形で書いて呼び出し=実行します。 ' LineWNum→矢印の線の太さを1とか2.25などと指定します。矩形の線の太さは2.25固定にしてあります。 ' aka→RGBの「Red」の値を指定します。 ' midori→RGBの「Green」の値を指定します。 ' ao→RGBの「Blue」の値を指定します。 '###################################################################################################### Sub MakeRoundSquareSet01(aka As Integer, midori As Integer, ao As Integer, LineWNum As Double) Dim myDocument As Document Dim TopNum01 As Variant 'まずユーザーに図形を挿入する高さ(縦の位置)を聞きます。 '点滅カーソルのあるページの100~700までの縦の位置を指定してもらいます。(単位はピクセル) '100だと上のほう、350だと真ん中へん、700だと下のほうに挿入されます。 '入力してもらう数値は150でも236でも何でもOKです。 TopNum01 = InputBox("配置する高さの位置を100~700の数字で指定してください") '「キャンセル」が押されたときのエラー回避処理 'ユーザーに高さを聞くときInputboxというものを使っていますが、 'Inputboxでは「キャンセル」が押されると、空文字(「""」と表記します)が '返事として返ってくるのでそれを利用します。 If TopNum01 = "" Then '「キャンセル」が押されたときの処理 Exit Sub 'Subプロシージャ(=このプログラム)自体を抜ける=終わる Else '押されなければ何もせず次へ End If '丸角矩形の作成 Set myDocument = ActiveDocument '操作対象となるファイルを、点滅カーソルのあるファイルに指定します。 With myDocument.Shapes.AddShape(Type:=msoShapeRoundedRectangle, Left:=100, Top:=TopNum01, Width:=100, Height:=50) '丸角矩形の生成 .Line.Weight = 2.25 '矩形の線の太さは2.25固定で。 .Line.ForeColor.RGB = RGB(aka, midori, ao) '線の色を設定する .Fill.Visible = msoFalse '線無しは .Line.Visible = msoFalse End With '矢印の作成 '矢印の終端や始端の形は以下の7種類から選べます。 'msoArrowheadNone 'msoArrowheadOval 'msoArrowheadStyleMixed 'msoArrowheadDiamond 'msoArrowheadOpen '|msoArrowheadStealth 'msoArrowheadTriangle| 'また、始端の形の設定は、上記の7つを「BeginArrowheadWidth 」で指定すれば良いようです。 Set myDocument = ActiveDocument '操作対象となるファイルを、点滅カーソルのあるファイルに指定します。 With myDocument.Shapes.AddLine(300, TopNum01, 250, TopNum01 + 50) '直線の生成 .Line.Weight = LineWNum '矢印の線の太さを設定する .Line.ForeColor.RGB = RGB(aka, midori, ao) '線の色を設定する .Line.EndArrowheadStyle = msoArrowheadOpen '終端の形を設定する .Select '矢印を選択 End With End Sub Sub 挿_丸矩セット_赤() '線の太さ「1」の矢印と、赤枠のテキストボックスを一括挿入します。 '「255, 0, 0」が「赤」を意味しています。 '最後の「1」が矢印の線の太さの設定値です。 Call MakeRoundSquareSet01(255, 0, 0, 1) End Sub '###################################################################################################### 'Excel2010で、開かれていない閉じたままのブック・Excel(xls)データを 'できるだけ速く読み込む方法(DAOにて) '###################################################################################################### Option Explicit Private Sub ReadByDao() 'VBE画面のツール→参照設定、にて、「Microsoft DAO 3.6 Object Library」にチェックを入れておきます。 Dim DB As DAO.Database '読込対象のXLSファイルのDAOオブジェクト用の変数 Dim RS As DAO.Recordset '読込対象のシートのDAOオブジェクト用の変数 Dim SrcXLFName As String '読込対象のXLSファイルのフルパス格納用の変数 Dim SrcSHTName As String '読込対象のシート名の格納用の変数 Dim WS01 As Worksheet '自ファイルのデータ転記対象のシートを格納(=指定)するためのオブジェクト変数 Dim i As Integer 'そのシートの行数を表すための変数 '読込対象としたいXLSファイルを指定する SrcXLFName = "D:\DAOテスト.xls" '読込対象としたいシートを指定する SrcSHTName = "読み込みテスト$" '「読み込みテスト」シートをシステムテーブルとして読み込む。 '「$」を付けるとシステムテーブルになる。 'データベースファイル(SrcXLFName)を開く。ここではxlsファイル。(=DAOとしてのデータベースを定義づけ) 'HDR=NO →「IMEX」の値を「=1」にしたときは、1行目を列名として読込む。(どうやら数値もテキストとして読み込まれるようです) 'HDR=YES →「IMEX」の値を「=1」にしたときは、1行目を列名として読込まない。(どうやら数値は数値、文字列は文字列として読み込まれるようです)(列名を読みたくない場合など) 'IMEX=1→表示されているセル書式の値でデータを吸い込む。(今回のテストでは完全にはそうはなりませんでした。よくわかりません。) 'Excel 8.0→「VBA Excel バージョン番号」でGoogle検索。「8.0」で2000でも2010でも動いた。 Set DB = OpenDatabase(SrcXLFName, False, False, "Excel 8.0;HDR=YES;IMEX=1") '読込対象のシートを開く。(DAOとしてのレコードセットを定義づけ) Set RS = DB.OpenRecordset(SrcSHTName) Set WS01 = Worksheets("Sheet1") 'データを吸い込むシートの定義(データを転記するシートの定義づけ) i = 2 '列名のことを考えて、 '読み込みデータを 2行目から入力したい場合は 2とする。 '「HDR=NO」にしたとき、列名も読み込んで '1行目から入力したいなら 1とする 'ここでは前者でテストしてます。 WS01.Range("A2:C30").ClearContents '読み込み先のファイルの行数が増減するといけないので、 '一応、転記するシートをきれいに空白しておく。 '前回よりデータ行数が少ないと、前回のデータが残ってしまうので。 '読込対象のレコードセット(シート)の最終レコードまでを読込む 'EOFはシートの最後じゃなくて、レコードとして入力された最終行 Do Until RS.EOF With RS 'Sheet1の A列・B列・C列に読み込んだデータを転記 WS01.Range("A" & i) = .Fields("氏名") 'レコードセット側のカレント行の「氏名」列の値を「Aのi」セルに転記 WS01.Range("B" & i) = .Fields("年齢") 'レコードセット側のカレント行の「年齢」列の値を「Bのi」セルに転記 WS01.Range("C" & i) = .Fields("性別") 'レコードセット側のカレント行の「性別」列の値を「Cのi」セルに転記 .MoveNext 'レコードセット側(読込データ側)を次のレコード(行)に移動 End With i = i + 1 '自ファイル側(Excelファイル側)も次の行に移動 Loop RS.Close DB.Close Set RS = Nothing Set DB = Nothing End Sub ' ' |
また、コメントを上に書くとわかりづらい、ということであれば、以降に示すようにコメントをプログラムの下に書けば結構見やすくなります。(コメントが目に入っても脳まで到達させないようにしやすい。)
もちろん、何度も言いますが、こんなことしなくても「コメントが目に入っても脳まで到達させないようにしやすくする」というのは誰にでもできますし、コメントを一発で消すとか、一瞬で必要なものだけ残す、のなんてだれにでもできます。
特にVBAではVBE自体も操作できますし、それがわかりづらいなら、いったん各モジュールをBAS形式でエクスポートしてから、Wordなどで不要なコメントだけ全部消して、インポートし直せば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 |
' ' Option Explicit '################################################################################################## 'アクティブなシートのA1セルの値にファイル名に使えない文字が含まれているかいないかのチェック事例。 '使えない記号が含まれていればエラーメッセージが出て、イミディエイトにTrueが表示されます。 '使えない記号が含まれていなければ、エラーは出ずに、イミディエイトにFalseが表示されます。 '################################################################################################## Sub test01() Dim TestStr01 As Variant TestStr01 = ActiveWorkbook.ActiveSheet.Range("A1") 'アクティブなシートのA1セルの値を取得 Debug.Print FnameNgStrChk01(TestStr01) 'その値を、FnameNgStrChk01()関数にて、 'ファイル名に使えない記号が混ざっていないかをチェックします。 '結果はイミディエイトウィンドウに出ます。 '使えない記号が含まれていなけエラーは出ずにFalseが表示されます。 '使えない記号が含まれていればエラーが出てTrueが表示されます。 End Sub '############################################################################# 'ファイル名に使えない文字のチェック用の関数。読み込み時、書き出し時、兼用。 '指定例:Debug.Print FnameNgStrChk01("ああ[あああ") ' 「 [ 」が含まれている旨のエラーが出て、 ' True(=ヒットした!含まれてた!という意味です)が返されます。 '使えない記号が含まれていればエラーが出てTrueが返ります。 '使えない記号が含まれていなけエラーは出ずにFalseが返ります。 '############################################################################# Function FnameNgStrChk01(ByVal str01 As Variant) As Boolean Dim ChkChr01 As Variant ChkChr01 = "" '変数「ChkChr01」に「""」を代入して初期化 '● 送られてきた値(str01の値)が空だったときのチェック '(一応、それぞれのパターンを書き出してみました。) If IsNull(str01) = True Then FnameNgStrChk01 = False Exit Function '送られてきた値がNullだったときはFalse(何もヒットしなかったよ!という意味です)を返して 'プログラムの実行を終わる。(本プログラムはAccessにも流用できると思いますが、 'NullのチェックはAccessの場合は必須です。) ElseIf str01 = "" Then FnameNgStrChk01 = False Exit Function '送られてきた値が空文字("")だったときもFalseを返してプログラムの実行を終わる。 Else 'それ以外の場合、つまり、チェックにひっかからなければ次へ End If '● ファイル名に使えない文字のチェック '(ヒットしたら、ヒットした文字を変数「ChkChr01」に代入します。 ' 以降の「● 最終処理」にてエラーメッセージを出すときに、どの文字がダメなのかを ' 変数「ChkChr01」を使ってユーザーに知らせたいためです。 ' なお、以下の「\」は半角の「¥」のことです。) If InStr(str01, "\") > 0 Then ChkChr01 = "\" '送られてきた文字列に「\」が含まれていたら、ChkChr01に「\」を代入します。以下同じような意味です。 If InStr(str01, "/") > 0 Then ChkChr01 = "/" If InStr(str01, ":") > 0 Then ChkChr01 = ":" If InStr(str01, "*") > 0 Then ChkChr01 = "*" If InStr(str01, "?") > 0 Then ChkChr01 = "?" If InStr(str01, """") > 0 Then ChkChr01 = """" If InStr(str01, "<") > 0 Then ChkChr01 = "<" If InStr(str01, ">") > 0 Then ChkChr01 = ">" If InStr(str01, "|") > 0 Then ChkChr01 = "|" '以上、Windowsの仕様によるもの(書き出し時に特に使います。読み込み時はOSがこの文字を含んだファイル名を作らせてくれないため、そもそもそのファイルを吸い込むことはありませんから、[と]だけのチェックになります。) If InStr(str01, "[") > 0 Then ChkChr01 = "[" If InStr(str01, "]") > 0 Then ChkChr01 = "]" '以上、Excelの仕様によるもの(書き出し時、読み込み時、両方使います) '● 最終処理 If ChkChr01 = "" Then FnameNgStrChk01 = False 'ChkChr01の値が空のままなら=何もヒットしなかったのなら、= ' =ファイル名に使えない文字が何も含まれていなければ、 'Falseだけ返して何もしない。 Else MsgBox "ファイル名チェックエラー:Excelのファイル名には使えない記号、「 " & ChkChr01 & " 」が含まれています。" FnameNgStrChk01 = True 'ChkChr01の値が空じゃないなら=ファイル名に使えない文字が含まれていれば、 'エラーメッセージで注意喚起して、Trueを返す。 End If End Function ' ' |
以下のプログラムはVBAじゃなくてUWSCのプログラムですけど、その場合も、例えばこんな感じでコメントが残ってるとすごくあとの修正がしやすいです。UWSCのプログラムコード作成は、VBEの画面のように至れり尽くせりではないので・・・。
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 |
' ' // // //デスクトップにあるJpeg画像を、いったんD:\WPIMG\にコピーしてFTPし、 //そのURLをもとにImgタグを自動生成する。 //「OnePress Image Elevator 」のかわりです。 //MySQL内に画像を置きたくないときに使えると思います。 //事前にBasp21のインストールが必要です。 //Win10Pro32bit、64bit、両方で動くと思います。 //事前にBasp21の最終バージョンのインストールが必要です。 //ただ、こちらは 「BASP21-2003-0211.exe」でも動きました。 //最新版のダウンロードは以下です。 // http://www.hi-ho.ne.jp/babaq/basp21.html // PCUserName = "user01" //自分が今開いているデスクトップのユーザー名です PCDesktopSrcJpegName = "src - コピー.jpg" //デスクトップに置いた白地の50×50のjpgをひな型に、それを右ドラッグコピーしてソース画像に使うのですが、右ドラッグすると必ずこの名前になるのでそれを利用します。 PCImgFolder01 = "D:\WPIMG\" //ソース画像を、ファイル名をリネームしつつ複製する先のフォルダを作り、それを指定します。ここではDドライブにWPIMGというフォルダを作り、それをコピー先に指定します。 FtpHostName = "FTPのホスト名" //プロバイダから指定されたFTPサーバー名です。「public_html」とかそういうものは要りません。IPアドレスでも良いかもです。基本、末尾には「/」要らないと思いますが、もしテストしてみて無いとダメなら少しプログラムを書き換える必要があります。もしくは、FtpUserDir01 で/を先頭に付けないか、です。それでだめならプログラムをそういう状況に合うように書き換えます。分からなかったら誰かに書き換えてもらってください。 FtpAccountName = "FTPのユーザー名" //プロバイダから指定されたFTPユーザー名です。メールやインターネット接続のためのユーザー名とはまた別のユーザー名となりますのでご注意ください。 FtpAccountPsw = "FTPのパスワード" //プロバイダから指定された、あるいは自分で変更したFTPパスワードです。こちらもメールやインターネット接続のためのものとは違うのでご注意ください。 FtpTildeName = "/~チルダがある場合その名前" // 「/」を先頭に書きます。無ければ""のままで。自分のホームページアドレスが「http://xxxxx.jp/~xxxxx/」のように「/~xxxxx/」の部分があるときは指定します。ただ、「/~xxxxx/」がある場合であっても実際にFTP送信テストしてみたらここが空白のほうが正常につながるということなら、ここは""のままとします。 HttpName = "http://" //httpやhttps?ご自分の環境に合わせて。https、まだ経験したことが無いのでよくわかりません。すみません。 FtpUserDir01 = "/「public_html」など、ルートの階層のディレクトリ名" // 「/」を先頭だけに書きます。末尾には要りません。なお、送信テストしてみて、もし逆に指定の必要が無いなら""のままで。 FtpSubDir01 = "/FTPのサブディレクトリ名。もしあれば。" // 「/」を先頭だけに書きます。末尾には要りません。無ければ""のままで。1階層目のサブフォルダの指定です。 FtpSubDir02 = "" // もし2階層目のサブフォルダがあれば「/」と共に書きます。無ければ""のままで。 FtpSubDir03 = "" // もし3階層目のサブフォルダがあれば。以下同文。 //画像のURLを生成するとき、FTPとしてのホスト名とURLとしてのホスト名前が違う時用の設定です。 //先頭に「/」を付けずに、「http://」以降のホスト名だけを指定します。必ず指定します。 //たとえば、FTPのホスト名には「ftp.」が付いているけど、実際の「http://」以降のホスト名には //それはついてない、という場合、ついてないほうのホスト名を指定します。 //URLに「/~xxxx」とチルダの名前も付いていたらそれは含めません。すでに「FtpTildeName」で指定していますので。 //FTPサーバ名と、URLの「http://」以降のホスト名が全く同じ場合は、FtpHostName の設定値とまったく同じ値になります。 URLHostName = "URL用のホスト名" GETTIME() //今現在の日時を取得 //取得した日時をもとに、画像のファイル名を生成します。 //「G_TIME_YY4」や「G_TIME_MM2」などはその取得した日付データから年や月を切り出すためのUWSCの関数です。 //そして「G_TIME_YY4」や「G_TIME_MM2」などの末尾に数字のあるものは文字列型で、数字の無い「G_TIME_YY」や「G_TIME_MM」は数値型か何かみたいです。 //「G_TIME_YY4」と「G_TIME_MM」を混在させるとエラーになる??(未調査)みたいですので、ここでは末尾に2や4のついた文字列型の切り出しデータで統一します。 fname01 = G_TIME_YY4 + "-" _ + G_TIME_MM2 + "-" _ + G_TIME_DD2 + "---"_ + G_TIME_HH2 + "-" _ + G_TIME_NN2 + "-" _ + G_TIME_SS2 + ".jpg" CopyDistFullPath = PCImgFolder01 + fname01 //デスクトップの「src - コピー.jpg」をコマンドプロンプトでコピーする際の、コピー先文字列を生成 DosCmd("copy <#DBL>C:\Users\" + PCUserName + "\Desktop\" + PCDesktopSrcJpegName + "<#DBL> <#DBL>" + CopyDistFullPath + "<#DBL>" ) //コマンドプロンプトにて、「src - コピー.jpg」をD:\WPIMG\へ日付ファイル名でコピー。「<#DBL>」はコマンドプロンプト上で使うダブルクォーテーションを意味しています。 ftp = CreateOLEObj("basp21.FTP") //Basp21の呼び出し ftp.Openlog( PCImgFolder01 + "samplelog.txt") //FTPアップロードのログファイルをD:\WPIMG\へ出力する設定にします。 ftp.Connect(FtpHostName, FtpAccountName, FtpAccountPsw) //FTPサーバへの接続。「Rc = ftp.Connect(FtpHostName, FtpAccountName, FtpAccountPsw) 」のように書くと、接続が成功したかしないかの戻り値が返ってくるので、それを基準にした条件分岐のコードも書けます。他の各Basp21コマンドもそうです。 ftp.Command ("pasv") //よくわかってないのですが、一応パッシブモードにします。ファイアウォールのせいでアップできない時用。ぼくんちは無くても大丈夫でしたが・・。不要なら「//」でコメントアウトしてもいいです。 //FTPへのアップロード用のパスを生成 FtpPutDirPath = FtpUserDir01 + _ FtpSubDir01 + _ FtpSubDir02 + _ FtpSubDir03 //アップロードの実行。 //最後の数字の「1」 はバイナリーモードでの送信を意味します。画像を送るときは1にします。 //詳しくは http://www.hi-ho.ne.jp/babaq/basp21f.html の //「●PutFile(local,remote[,type]) : リモートへファイルを送信」をお読みください。 //その他のファイルを送るときの送信形式は以下の設定をご参考に。(上記Webページより引用) // 0 : ASCII(省略値)。txt/html などのテキストファイルの場合。 // 1 : バイナリ。jpg/gif/exe/lzh/tar.gz などのバイナリファイルの場合。 // 2 : ASCII + 追加(Append)モード。 // 3 : バイナリ + 追加(Append)モード。 ftp.PutFile(CopyDistFullPath, FtpPutDirPath, 1) ftp.Close //FTPサーバから切断 //アップロードした画像のURLを、冒頭で設定した各種情報をもとに生成します。 ImgURL = HttpName + _ URLHostName + _ FtpTildeName + _ FtpSubDir01 + _ FtpSubDir02 + _ FtpSubDir03 + _ "/" + fname01 //WordPressに貼り付けるための、アップした画像にリンクする Imgタグを生成します。「<#DBL>」はHTMLで使うダブルクォーテーションを意味しています。元画像の70%の大きさで表示する設定です。 ImgTAG = "<a href=<#DBL>" + ImgURL + "<#DBL> target=<#DBL>_blank<#DBL>>" + "<img src=<#DBL>" + ImgURL + "<#DBL> alt=<#DBL><#DBL> width=<#DBL>70%<#DBL> height=<#DBL>70%<#DBL> ></a>" SENDSTR(0,ImgTAG) //生成したタグをクリップボードへ送ります。 // ' ' |
★ 究極にコメントが多い例
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 |
' ' Option Explicit Sub ReadByADO01() '★ 変数設定とオブジェクト変数について Dim Cn As ADODB.Connection '読込対象のXLSファイルの「ADO接続文字用のオブジェクト」用の変数 '文字列型かとおもったらオブジェクト型でした・・・。 'DAOでいうと、DAOでよく使われる「db」とか「dbs」といった 'オブジェクト(あるいはオブジェクト変数)と同じ・・・って感じなんですね。 'DB=Cn=というオフジェクト、つまりVBAプログラム内で '「ファイルというオブジェクト」を操作できるようにするために利用します。 'そのためのオブジェクト変数。 'CnにExcelファイルのパスやその他の設定をこの変数に代入することで、操作可能となります。 Dim Rs As ADODB.Recordset '読込対象のシートの「ADOデータ範囲?設定用のオブジェクト=レコードセット」用の変数。 'ADOやDAOでは、純粋なExcelオブジェクトのように '「Excelシート(セル)の値やAccessテーブルをダイレクトにいじる」というこができません。 'いったん「レコードセット」と呼ばれる、「動的な表を一時保管する器」の中に、 '加工対象の表、あるいはシートの中の任意の表範囲をいったん仮格納する必要があります。 'で、その中でいろいろといじってから、その結果を、元のシート(セル)等々に返します。(反映させます。) 'ここでの例の場合は「Rs」というオブジェクト変数に、 'シートの名前・あるいはSQL文とその他の設定値を代入することで、 'VBAプログラム内でレコードセットが操作できるようになります。 '「Rs」は、そのためのオブジェクト変数です。 Dim SrcXLFName As String '読込対象のXLSファイルのフルパス格納用の変数 Dim SrcSHTName As String '読込対象のシート名の格納用の変数 Dim StrSQL01 As String Dim WS01 As Worksheet '自ファイルのデータ転記対象のシートを格納(=指定)するためのオブジェクト変数 Dim i As Integer 'そのシートの行数を表すための変数 '================================== '★ ちょと関係のある脱線:「オブジェクト変数」とは? '以降の(01)~(06)の内容をもう少し詳しく書き換えた以下のURLのほうもご参考にしてみてください。 ' 『用語:「オブジェクト変数」とは?(ついでに「コレクション」についても少し・・・)』 'https://euc-access-excel-db.com/tips/ct90_yougo/obujekuto-hennsuu-toha01 ' '「オブジェクト変数」とは、文字列や数値ではなく、「オブジェクト」という '「ユニット丸ごと・その機能丸ごと」を「代入」できる変数のことです。 ' '「オブジェクト」とは「セル、シート、ブック、ピボットテーブル、コマンドボタン、エラー管理機能」等々、 ' 目に見える・見えないに関係なく、各種の機能・メニューコマンドたち」のことをさします。 ' 'イメージ的には・・・、 ' 通常の変数には文字列か数値やYes/Noなどしか代入できませんが、 '「オブジェクト変数」には '「前述のような”オブジェクト”が持つ機能丸ごとも含めて、オブジェクトそのもの」を ' 代入できる・・・、そんなイメージです。 ' 'で、実際に「オブジェクト変数」にオブジェクトを代入する、といった場合・・・、 ' '例えば(のちにも出てきますが)、「静的な表-意外とわかりにくい」という名前の「シート」丸ごとを '「Sht01」というオブジェクト変数に代入した場合は、次のようなことができます。 ' '(01)「静的な表-意外とわかりにくい」という長ったらしい名前の「シート」丸ごとを ' プログラムの中では「Sht01」という「仮名」で書けることになります。 ' プログラムがすっきりとします。 ' '(02)「静的な表-意外とわかりにくい」という名前の「シート」丸ごとを ' プログラムの中では「Sht01」という「オブジェクト」として「操作」、 ' できるようになります。 ' '(03)「操作」とは「メソッド」という命令を使う、という意味でもあります。 ' 普通の変数では、文字列か数値などを加工することしかできませんが、 ' オブジェクト変数に対しては、「メソッド」というオブジェクト専用の命令が ' 使えるようになります。 ' それで「オブジェクト」を「操作」「動かす」ことをします。 ' ちなみに、各「メソッド」たちは特定のオブジェクトに特化・紐付いた命令たちです。 ' 「メソッド」を使うと、オブジェクト(=プログラムとしては「オブジェクト変数」のこと)を ' 自由に「動かす」ことができるようになります。 ' (=オブジェクトの持つ、機能を利用する・動かす、といったことができます。) ' メソッドには ' 例えば「複数ワークシート管理機能(WorkSheets)」というオブジェクトなら、 ' 次のような専用のメソッド(命令)があります。 ' ・Move(××シートの後ろに移動しろ) ' ・PrintOut(印刷プレビューを表示しろ) ' ・PrintPreview(印刷プレビューを表示しろ) ' ・Select(シートを選択しろ) ' ・Copy(シート内のすべてのセルの値や機能はもちろん、シートの持つ機能や設定値等々丸ごと全てをコピーしろ) ' ・Delete(シートを削除しろ) 'すべてのオブジェクトに、同じメソッドが紐付いているわけではありません。 'オブジェクトごとに、使えるメソッドが異なります。 '(03)「オブジェクト(=オブジェクト変数)」が扱えてオブジェクトが動かせるようになると、 ' 各オブジェクトの「プロパティ(性質・特性・各種設定)」の「設定値」や「入力値」などが ' 取得できるようになります。 ' それらを取得することで、 ' 例えば、「もしこのオブジェクトのこの設定値がこの値の場合は、こういう風に動け」・・・ ' ・・・という形の命令を書くことができます。 ' つまり、オブジェクトに対して、「おいおまえ、ロボットのように動け」と命令できるわけです。 ' 普通の変数の場合は、数値や文字列をひったり貼ったり集計したりができるくらいで、 ' 「ロボットのように動け」と命令できません。 ' できたとしも、実際に自動的にロボットのように動くわけでもありません。 ' でもオブジェクト変数があるおかげで、逆にそれがとてもやりやすくなります。 ' '(04)「オブジェクト変数」を使うことで、「オブジェクト」を「まるでロボットかのように」、 ' 動かすことができるようになります。 ' 「メソッド」や「ステートメント」といった命令語たちや ' 「プロパティ」と呼ばれるオブジェクトの持つ各種設定値を使って。 ' '(05)「シートがもつ機能の設定値」・・・、例えば「セルの値」「数式」などを取得することが簡単になります。 ' 例えば、「静的な表-意外とわかりにくい」という名前のシートの、A1セルの数式を取得したい場合は、 ' 「Worksheets("静的な表-意外とわかりにくい").Range("A1").Formula」 ' と書くことで取得ができます。 ' ' が、その「静的な表-意外とわかりにくい」というシートの機能丸ごとを ' オブジェクトとして、「Sht01」というオブジェクト変数に代入してしまうと、 ' 「Sht01.Range("A1").Formula」 ' と短く書いても同じ数式が取得できます。 ' ' ついでに言うと、「セルA1」を表す「Range("A1")」もオブジェクト変数に代入してしまうことができます。 ' ' その場合、例えば「Sht01」のA1セル・・・、 ' ・・・A1セルはVBAでは「Range("A1")」と書き表しますが、 ' それを「CelA1」というオブジェクト変数に代入したとすると ' 「Worksheets("静的な表-意外とわかりにくい").Range("A1").Formula」と長ったらしく書かなくても、 ' 「CelA1.Formula」と、とても短く書くことができます。 ' ' メソッドで言うと、「Copy(=コピーしろ)」という命令を使うことで、 ' 「セルA1をコピーしろ」というプログラムを ' 「Worksheets("静的な表-意外とわかりにくい").Range("A1").copy」と書くのではなく、 ' 「CelA1.Copy」と、短く書けてしまいます。 ' そして、このコピーの場合、セルの値だけでなく、数式もセルの色書式も、 ' セルのもつ機能のすべてをコピーします。 ' (セルA1に色を付けてから「CelA1.Copy」とやると、その直後にどこか適当なセルに ' 「貼り付け」をすると、セルの数式も色も張り付きます。) ' '(06) なお、オブジェクト変数にオブジェクトを代入するには「Set」という命令を使います(それが必要です)。 ' プログラムには、英語の文法のように「構文」があるのですが、 ' その「構文」としては「Set= ××××××」という構文になります。 ' 普通の変数の場合は「=」記号だけで数値や文字列の代入ができますが、 ' オブジェクト変数の場合は、「Set= ××××××」という構文が必要になります。 ' 前述の各例も、省略してしまいましたが、「Set= ××××××」という命令を書くことが ' 前提となっています。 '脱線終わり '================================== '★ 以下、メインプログラムです。 SrcXLFName = "d:\test01\tes1_ADO.xlsm" '読み込みたい先のファイルのフルパスを指定 ' SrcXLFName = "\\ファイルサーバー名\tes1.xls" ' SrcXLFName = "\\ファイルサーバー名\tes1-2.xlsm" SrcSHTName = "静的な表-意外とわかりにくい$" '「静的な表-意外とわかりにくい」という名前のシートを 'システムテーブルとして読み込む設定をする。 '「$」を付けると「システムテーブルとして読み込む」 'という意味になる。 Application.ScreenUpdating = False 'Excelの画面描画をいったん停止。今の画面のまま変化させないようにする。 Set Cn = New ADODB.Connection 'ADOにてのデータ接続(ファイル内容の読み込み)ができるようにするための準備 Set Rs = New ADODB.Recordset 'ADOにてのレコードセット(シート内データ範囲?)が作れるようにするための準備 'ADOで読込先のファイルに接続。(読込先のファイルを開く) '------------------------------------------------------------------------------------------------ 'ACEエンジン系のADO操作(2007以降のxlsm・xlsx・accdb?用のファイルの開き方) 'でもテストしたところ、2000~2003のxlsのファイルもこちらで読めてしまいました。 'しかもJETのように数値が読み込まれないケースがありませんでした。 '複数のクロス集計表があるシート=列名のセルがぐっちゃぐちゃにとびとびに存在するシートの場合は 'こちらのACEエンジン系でやるほうがいいかもです。 '後述の JET形式のように数字が読み込まれないということがないので。 'JET形式では、元シートの8行目だか5行目までを読みにいき、最初に見つかったセルの書式で 'データ型を勝手に決める、というような雰囲気で列のデータ型を決めているようですが、 'その際、クロス集計表が複数あるシートだと、列名が書かれたセルの位置は 'シートの一行目ではなく、ぐっちゃぐちゃなっていて、どこにあるかわかりません。 'で、ADOだかExcelだかが、列名のセルを読んだどき、1行目に列名が無いもんですから、 '列名であっても列名と認識できず「あ、この列は文字列型だ」と判断してしまい、 'データのなる数値のほうを「文字列じゃないから読まなくていい」みたいな感じになってしまって '読んでくれないことがあります。 'ACE形式での読み込みではそれがなく、文字列だろうが数値だろうが、一応、値を読み込んでくれます。 'また、1行名が全部列名で、1シートに1つの動的な表だけ、という場合なら、JET形式での読み込みでも '「読み込めないセルが出てくる」、ということはありません。 ' '(★★★注:後日判明。後述。 ' 新しいJET系のコードでは自動決定された列のデータ型と異なる ' データでも読み込めました。「;IMEX=1」を追記したほうのコードです。 Cn.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & _ "Data Source=" & SrcXLFName & ";" & _ "Extended Properties=""Excel 12.0;HDR=Yes;IMEX=1;Readonly=False""" '------------------------------------------------------------------------------------------------ 'JETエンジン系のADO操作(2000~2003のxls・mdb用のファイルの開き方) 'こちらのコードを使う際は、この前段階の「SrcXLFName = "d:\test01\tes1_ADO.xlsm"」の '内容を、SrcXLFName = "d:\test01\×××.xls" と、xls(2003以前形式)にしてください。 'もちろん、「d:\test01」フォルダの中には、新たに1つ、xlsmのファイルの内容をxlsファイルに '作り直したものを置いておきます。 ' '複数のクロス集計表があるシート=列名のセルがぐっちゃぐちゃにとびとびに存在するシートの場合は '数値が読み込まれない場合があります。 'なのでその場合はACE形式の読み込みのほうがいいかも。 'きっちりした動的な表ならこちらでもOKかと思います。 '(後日判明。以下のコードは自動決定された列のデータ型と異なるデータは ' 読み込めないっぽいです。 'cn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=" & SrcXLFName & ";" & _ "Extended Properties=""Excel 8.0;HDR=Yes;"";" ' '★★★注:成功したコード!!! さらに後日判明!! ' 「Extended Properties」に「;IMEX=1」を追記すると、 ' セルに入力された値に関わらず、以下のコードで全値を読み込めました。 ' 僕の環境だけだといけないので、皆さんもご自分の環境でお試しください。 'Cn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=" & SrcXLFName & ";" & _ "Extended Properties=""Excel 8.0;HDR=YES;IMEX=1""" '------------------------------------------------------------------------------------------------ '「レコードセット」を開くためにSQL文を設定。 '「レコードセット」は、ADOやDAOにて「各種操作ができる表」のことです。 ' ADOやDAOでは、ExcelVBAのように、ExcelシートやAccessテーブル・セルをダイレクトはいじれないので、 ' いったん、「レコードセット」と呼ばれる、ある意味「一時保管用の表」の中に、 ' 加工対象の表、あるいは表範囲を仮格納します。 ' そしてその中でいろいろといじってから、その結果を、元のシートやテーブルに返し(反映させ)ます。 ' Excelの場合は、そのレコードセットは何も指定しなければシート丸ごとか、 ' セル範囲を指定すれば、シートの一部・・・、となります。 ' StrSQL01 = "SELECT * FROM [" & SrcSHTName & "A1:N15" & "]" 'このようにシート名のあとにセル範囲を追記すると、そこまでの範囲を見に行って、その範囲内で、データが入力されている部分を自動判別してくれて、レコードセットを作ってくれます。 StrSQL01 = "SELECT * FROM [" & SrcSHTName & "]" 'セル範囲を指定しないと、シート丸ごとのすべての範囲を見に行って、データが入力されている部分を自動判別してくれて、レコードセットを作ってくれます。 'SQL文にて、レコードセットを開く。「レコードセット=データの入力された範囲?」を決定しつつ。 Rs.Open StrSQL01, Cn, adOpenStatic, adLockOptimistic, adCmdText Set WS01 = Worksheets("Sheet2") 'データを吸い込むシートの定義(データを転記するシートの定義づけ) i = 2 '列名のことを考えて、 '読み込みデータを 2行目から入力したい場合は 2とする。 '「HDR=NO」にしたとき、列名も読み込んで '1行目から入力したいなら 1とする 'ここでは前者でテストしてます。 WS01.Range("A2:C30").ClearContents '読み込み先のファイルの行数が増減するといけないので、 '一応、転記するシートをきれいに空白しておく。 '前回よりデータ行数が少ないと、前回のデータが残ってしまうので。 Do Until Rs.EOF 'SQL文で抜き出したレコードセットの最後の行(=「EOF」)まで。1行ずつ読み行く。 '※「Loop」の行までの作業を繰り返します。 ' Debug.Print Rs(0) & "---" & Rs(1) & "---" & Rs(2) & "---" & Rs(3) & "---" & Rs(17) & "---" & Rs(18) & "---" & Rs(19) ' '目的のシートの A列・B列・C列・・・・に、読み込んだデータを転記 ' '列を列名で指定する場合のやり方 ' WS01.Range("A" & i) = Rs.Fields("F1") 'レコードセット側のカレント行の「F1」列の値を「Aのi」セルに転記 ' WS01.Range("B" & i) = Rs.Fields("F2") 'レコードセット側のカレント行の「F2」列の値を「Bのi」セルに転記 ' WS01.Range("C" & i) = Rs.Fields("F3") 'レコードセット側のカレント行の「F3」列の値を「Cのi」セルに転記 ' WS01.Range("D" & i) = Rs.Fields("F4") 'レコードセット側のカレント行の「F4」列の値を「Dのi」セルに転記 ' ' WS01.Range("G" & i) = Rs.Fields("F18") 'レコードセット側のカレント行の「F18」列の値を「Gのi」セルに転記 ' WS01.Range("H" & i) = Rs.Fields("F19") 'レコードセット側のカレント行の「F18」列の値を「Hのi」セルに転記 ' WS01.Range("i" & i) = Rs.Fields("F20") 'レコードセット側のカレント行の「F20」列の値を「iのi」セルに転記 ' '------------------------------------------------------------------------------------------------ '列を列名で指定する場合のやり方 WS01.Range("A" & i) = Rs.Fields(0) 'レコードセット側のカレント行の「F1」列の値を「Aのi」セルに転記 WS01.Range("B" & i) = Rs.Fields(1) 'レコードセット側のカレント行の「F2」列の値を「Bのi」セルに転記 WS01.Range("C" & i) = Rs.Fields(2) 'レコードセット側のカレント行の「F3」列の値を「Cのi」セルに転記 WS01.Range("D" & i) = Rs.Fields(3) 'レコードセット側のカレント行の「F4」列の値を「Dのi」セルに転記 WS01.Range("G" & i) = Rs.Fields(17) 'レコードセット側のカレント行の「F18」列の値を「Gのi」セルに転記 WS01.Range("H" & i) = Rs.Fields(18) 'レコードセット側のカレント行の「F18」列の値を「Hのi」セルに転記 WS01.Range("i" & i) = Rs.Fields(19) 'レコードセット側のカレント行の「F20」列の値を「iのi」セルに転記 ' '------------------------------------------------------------------------------------------------ Rs.MoveNext '読み取り先のデータ(SQL文で抜き出したレコードセット)の次の行に移動 i = i + 1 '自ファイル側(Excelファイル側)も次の行に移動 Loop Rs.Close: Set Rs = Nothing ' 作ったオブジェクトの破棄:一応メモリリークを起こさないように?作ったオブジェクトをメモリから消す Cn.Close: Set Cn = Nothing ' 同上 Application.ScreenUpdating = True 'Excelの画面描画を再開。画面の変化が普通に表示されるようにする。 End Sub ' ' |
- 投稿タグ
- ExcelVBA, Excelの独学, Excel連携VBA, パソコンでの自動化, ビジネスパソコンの基礎, 自動化