いかたけの備忘録

忘れっぽい

今年やったこと

飲みに行って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ヶ月のサマリーのシートを作る事を考えましょう。先ほどの何らかの処理が拡充され、定型フォーマットが各シートに適用されたと考え、こんな感じになったとします。
f:id:ikatake:20191212231155p:plain
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でした」の続きが読めるのではないでしょうか。楽しみです。

追伸

ところで、皆さんVBAの書き方を調べるとき、どうやってますか?私は検索でガーッと2,3個ページを読んでなんとなく使ってるんですが、イマイチ効率が悪い気がしています。あと、これは共感していただけるか判りませんが、なんかVBAの情報を載せているGoogle上位のサイトって若干妙なのが多くないですか?また、VBAを体系的に勉強したことがないので、おすすめの本があれば教えてください。

宣伝

つくりおきアドベントカレンダーにも寄稿しています。見る必要の無い記事です。
tsukurioki.hatenablog.com

*1:私は昨日まで19連勤でした。