今年やったこと
飲みに行って2次会の会計を立て替えて、翌日に請求したりするときに、KyashやPayPayで支払いしてもらうようにした。
電車賃みたいに現金の方は切り上げで徴収する。若手はキャッシュレスで払ってくれて、おじさんたちは現金払いが多い。
VBAで失敗したことを振り返る2019
この記事はSpreadsheets/Excel Advent Calendar 2019 12/14(土) の記事です。
adventar.org
昨日はid:minemuracoffeeさんの「クラスの美少女の彼氏がExcelでした」の第6話でした。
Excelラブコメと思わせつつ、急にバトルグルメ感が出てきました。今進んでいるところが起承転結の「承」だとすると、この先の転・結が楽しみですね。
今回は今年2019年にVBAで失敗したことを書いていきたいと思います。1年間の失敗を振り返って、来年は同じ失敗をしないようにしたいものです。
1.if文の条件式が全部評価されるとは知らなかった。
具体的に何を作っていたのかをサッパリ忘れてしまったので、例で書きます。
- 1ヶ月分の出勤簿を作ります。
- 当月1日から最終日まで、1日1シートを作成します。
- シート名は日付とします。
- 土日は出勤簿を作成しません。*1
- さらに何かしら処理がありました。
確か書いたのが以下のようなスクリプトでした。
Option Explicit Sub enjoy() Dim dt As Date Dim sht As Worksheet dt = DateSerial(Year(Date), Month(Date), 1) Do While Month(dt) = Month(Date) Set sht = Nothing If makeSheet(dt, sht) And 何かの処理(dt, sht) Then さらに何かの処理 End If dt = dt + 1 Loop End Sub Function makeSheet(dt As Date, ByRef sht As Worksheet) As Boolean makeSheet = False If ((Weekday(dt) <> vbSaturday) And (Weekday(dt) <> vbSunday)) Then Set sht = Worksheets.Add sht.name = Format(dt, "m月d日") makeSheet = True End If End Function Function 何かの処理(dt As Date, sht As Worksheet) As Boolean 何かの処理 = True sht.Cells(1, 1) = "日付" sht.Cells(1, 2) = Format(dt, "yy年m月d日") End Function Private Sub さらに何かの処理() End Sub
失敗していたのは下記の部分です。
If makeSheet(dt, sht) And 何かの処理(dt, sht) Then
書いた意図としては、makeSheet関数で作ったシートのオブジェクトをbyrefで受けて、次の条件判定である何らかの処理(何を判定していたかを忘れたので、エラー要因になる処理を適当に記載しています…。)に進めようとしていました。土日でシートを作らない場合は戻り値がfalseになるから、「何らかの処理」は動かないだろう。と思っていたところ、完全に失敗しました。VBAではANDの左側が成立していない場合でも右側の処理が走るそうです。
私は初めてちゃんとプログラミングを勉強したのがC言語でしたので、条件式の中身を評価して成立しない事が判った時点で処理が中断されると思っていました。VBAは全部実行して評価するんですね。なにそれ、プロセッサの無駄遣いなのでは…?
当該処理を書き直すと以下のようになります。えっ、ダサ…。
'If makeSheet(dt, sht) And 何かの処理(dt, sht) Then If makeSheet(dt, sht) Then If 何かの処理(dt, sht) Then さらに何かの処理 End If End If
2.書き捨てるスクリプトでもちゃんとしよう。
話は変わりますが、皆さんの職場では働き方改革、進んでますでしょうか。単純作業は極力減らして残業を抑えないといけませんが、人手不足で仕事をお願いする人もなかなか居ません。あと単純作業は眠くなるので、あんまりやりたくないですね。そんな労働者の味方がVBAです。
先ほど作った出勤簿から今度は1ヶ月のサマリーのシートを作る事を考えましょう。先ほどの何らかの処理が拡充され、定型フォーマットが各シートに適用されたと考え、こんな感じになったとします。
C6に日付、F30に1日の総労働時間が入っているので、これを1シートに纏める方法を考えましょう。
Sub collectWorkTime() Dim sh As Worksheet Dim dt As Variant Dim wt As Variant Dim new_sh As Worksheet Dim row As Integer Set new_sh = Worksheets.Add row = 3 For Each sh In Worksheets new_sh.Cells(row, 3) = sh.Range(C6) new_sh.Cells(row, 4) = sh.Range(F30) Next End Sub
はい、これを実際にやらかしました。C6とF30をダブルクォートで括っていないので変数と解釈され、「アプリケーション定義またはオブジェクト定義のエラーです。」になりました。
Option Explicitしてれば、未定義変数で見つかるのですが、書き捨てるつもりでサボっていたので、10分ぐらい悩むことになりました。昨日ハマったので急遽この記事に書いて供養することにしました。
今回の投稿は以上です、新技術でも高度なテクニックでもありませんが、基本に立ち返ってVBAを上手く使って、単純作業を減らしていきたいですね。
最後までご覧いただきまして、ありがとうございました。
明日はadvent calendarに登録がないので、ミネムラコーヒー先生の「クラスの美少女の彼氏がExcelでした」の続きが読めるのではないでしょうか。楽しみです。
*1:私は昨日まで19連勤でした。