【VBA】ファイル間のコピー作業を自動化するマクロの作成

## はじめに
業務の傍らで、VBAを使って作業効率化した時のことを投稿にまとめます。

## 対象者
- VBA（プログラミング）初学者
- Excel作業の効率化を考えている人

## 前提知識
### マクロとは
- 処理を自動化するための機能です。主に作業記録や自動化に適しています
- Excelなどのアプリケーション内での操作を記録して再現することで、繰り返し行う作業を自動化し、作業効率を向上させることができます

### VBAとは
- ExcelやAccessなどのOffice製品で使えるプログラミング言語です
- マクロ単体でも操作を記録・再生はできますが、VBAが使えるとより複雑な処理や制御が行えます

### マクロとVBAの違い
マクロが**機能**であるのに対し、VBAは**プログラミング言語**です。
つまり、マクロを作成するための手段の1つとして、VBAがあります。

### マクロを使用するときの注意点
#### 1.業務が属人化しやすい
- ##### 特定の社員しか作成・編集できない
作成した社員しか修正や改善ができず、他の社員が業務を引き継ぐ際に大きな負担となる可能性があります。

- ##### マクロのブラックボックス化
コードが複雑になると、その仕組みが理解しづらくなり、どこでエラーが発生しているのか特定するのが難しくなります。

- ##### ドキュメント化の重要性 
マクロの内容を詳細にドキュメント化しておかないと、後からトラブルが発生した場合に、対応が遅れてしまう可能性があります。

#### 2. マクロウイルスへの感染リスク
- ##### 外部からのファイル
インターネットからダウンロードしたマクロ付きのファイルを実行することで、ウイルスに感染するリスクがあります。

- ##### セキュリティ設定
マクロの実行を許可する設定になっている場合、悪意のあるマクロが実行されてしまう可能性があります。
- ##### 定期的なセキュリティ対策
アンチウイルスソフトの導入や、OSのアップデートなど、定期的なセキュリティ対策を行うことが重要です。

#### 3. 自動化できる範囲が限定的
- ##### より複雑な業務の場合
複雑な判断や柔軟な対応が必要な作業は、[RPA](https://www.noc-net.co.jp/blog/2021/03/column_415/)など他のツールが適している場合もあります
- ##### 人による判断が必要な作業
人が判断して行う必要がある作業は、マクロだけでは自動化できません
- ##### システムとの連携
他のシステムとの連携が必要な場合、マクロだけでは対応できないことがあります

## 使用するファイル
説明の関係上、**ファイル1**と**ファイル2**と定義します。
- **ファイル1**：業務で実際に運用されているリスト（コピー元）
- **ファイル2**：入力漏れがないかをチェックするためのリスト（コピー先）

::: note info
「前置きは良いから、早くコードを見せてくれ」という方は、[こちら](#実際のコード)からスキップしてください。
:::

### 共通点
- A列〜M列までが同じ値であること

## 目的
**ファイル1の内容をファイル2にコピーする。**

### 入力作業手順（手動で行う場合）
1. ファイル1とファイル2を開く
1. ファイル1で更新した行のA列〜M列セルの値をコピーする
1. ファイル2で更新したい行のA列〜M列セルの値に貼り付けする
1. ファイル2を上書き保存する

## 問題点
- 手動で入力する手間と工数がかかる
- コピペミスをしてしまう可能性がある
- 作業工程や範囲が毎回決まっている単純作業（であるにも関わらず手動作業）

## 解決方法
### 結論
- マクロでコピペ作業を自動化する

### 入力作業手順（マクロを実行した場合）
1. マクロを登録したボタンを実行する
1. ファイル1を選択するダイアログが開く
1. コピー元のxlsxファイルを選択する
1. ファイル2を選択するダイアログが開く
1. コピー先のxlsxファイルを選択する
1. コピーが成功したら、メッセージボックスが表示される

### 懸念点
- プログラムの不具合やエラーでコピーが失敗する
- プログラムを作成した手間よりも手動作業の効率が上回る
- ループ処理で時間がかかって、手動の方が結局早く終わる

### 期待できる効果
- 毎回数分〜数十分かけていた作業をほぼ**１クリック**で完了できる

### 代替案
- ファイル1のコピー対象の列（A列からM列）までを一括コピーする。そしてファイル2に貼り付ける
#### 懸念点
- 手動であるのに変わりはない
- 入力ミスのリスクが無いわけではない（例えばフィルターをかけてたなどで、コピペする列がズレるなど）
- メタ的なことを言うと、これを採用したらこの記事はここで終わってしまう

## 実際のコード
::: note warn
以下のコードは正解ではなく、あくまで一例です。
:::

```vb
Sub SyncColumns()
  Dim wb1 As Workbook
  Dim wb2 As Workbook
  Dim ws1 As Worksheet
  Dim ws2 As Worksheet
  Dim lastRow As Long
  Dim i As Long
  Dim j As Long
  Dim filePath1 As String
  Dim filePath2 As String

  With Application
    .ScreenUpdating = False
    .Calculation = xlCalculationManual
  End With
  
　'ダイアログを開く
  filePath1 = Application.GetOpenFilename("Excelファイル(*.xlsx", , "ファイル1の選択")
  If filePath1 = "False" Then Exit Sub

  filePath2 = Application.GetOpenFilename("Excelファイル(*.xlsx", , "ファイル2の選択")
  If filePath2 = "False" Then Exit Sub

  'ワークブックを開く
  Set wb1 = WorkBooks.Open(filePath1)
  Set wb2 = WorkBooks.Open(filePath2)
  
　'ワークシートを指定する
  Set ws1 = wb1.Sheets("Sheet1")
  Set ws2 = wb2.Sheets("Sheet1")

　'最終行の取得
  lastRow = ws1.Cells(ws1.Rows.Count, "A").End(xlUp).Row
  

  For i=1 To lastRow
    For j=1 To 13 'M列まで繰り返す
       ws2.Cells(i, j).Value = ws1.Cells(i, j).Value 'ファイル1のワークシートのM列までのセルをファイル2のワークシートにコピーする
    Next j
  Next i

  wb2.Save
  wb1.Close SaveChanges:=False '保存せずにファイルを閉じる
  wb2.Close SaveChanges:=True '保存したらファイルを閉じる
  MsgBox "データのコピーが完了しました"
  Exit Sub

  With Application
    .ScreenUpdating = True
    .Calculation = xlCalculationAutomatic
  End With
ErrorHandler:
  MsgBox "Error" & Err.number & ":" & Err.description
End Sub
```

### 補足
- `Sub, End Sub`: プロシージャー名（いわゆるマクロの名前）のことで、**複数の処理を一つにまとめた**ものです。プロシージャー名に始まりEndを付けたSubで終わります
- `Dim`: 変数宣言をします。`As`を使うことでデータ型を指定することができます
- `Application.Calculation`: 数式の計算モードを設定するプロパティです。`xlCalculationManual`で手動計算、`xlCalculationAutomatic`で自動計算に変更します
- `Application.ScreenUpdating`: マクロ実行時に描画を停止・開始する機能です
- `GetOpenFilename`: [ファイルを開く] ダイアログボックスを表示させます。引数にダイアログの名前、ファイルの種類（.xlsx）などを指定することができます
- `Set`: **オブジェクトへの参照**を変数に代入します。オブジェクトの参照とは、あるオブジェクトのメモリ上の場所を示すような「住所」です
- `With, End With`: 単一のオブジェクトに対して、一連の処理を実行することができます。Withステートメントを記述することにより、コードが簡潔になります
- `For Next`: 繰り返し処理（ループ処理）を実行するVBA構文です。変数が開始数値から終了数値になるまで繰り返します

## おまけ
### VBAのデバッグ方法の例
- #### イミディエイトウインドウに値を出力
   - ##### デバッグコードの追加
        以下のコードを確認したい処理の下に追加します
      ```
      Debug.Print 値
      ```

   - ##### イミディエイトウインドウの開き方
      1. VBAエディタのメニューから「表示」→「イミディエイト」を選択するか、ショートカットキー（Ctrl+G）で表示します
      1. プロシージャ（Subプロシージャなど）を実行することで、イミディエイトウインドウに実行結果が表示されます。具体的な実行方法は次の項目にまとめます
      1. 以下はイミディエイトウインドウの表示例です
      ![immediate.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677000/27625794-edc4-3872-96bd-b941e3cc8691.png)

    - ##### プロシージャの実行方法
      - `F5キー`： 実行したいプロシージャ（Subプロシージャなど）を選択した状態で、F5キーを押すと、そのプロシージャから実行が始まります
      - `実行ボタン`： VBAエディタのツールバーにある実行ボタンをクリックします
       ![button_action_byVBA.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677000/ee198278-98f0-a2a6-fc6c-07c7937f7b46.jpeg)

      - `ワークシート上のボタンから実行`： 「開発」タブ →「挿入」→ 「フォームコントロール」からボタンを作成し、作成したマクロを登録することで実行できます
      ![create_form_button.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677000/f8cb1636-f838-4569-7744-ea110d06614e.jpeg)


- #### ブレークポイント
   - ##### ブレークポイントの設定方法
      - 中断させたい行の左側の余白をクリックします。 赤い丸印が表示され、ブレークポイントが設定されます
      - ショートカットキーのF9キーを押すことでも、ブレークポイントを設定・解除できます
    ![breakpoint.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677000/a6d641bc-7c6d-80a0-746d-2d472d4294b1.png)

   - ##### ブレークポイントの使い方
      - ###### デバッグの開始
         F5キーを押すか、「デバッグ」メニューから「デバッグの開始」を選択します
      - ###### ブレークポイントでの停止
         プログラムがブレークポイントに到達すると、実行が一時停止し、その時点での変数の値などを確認できます
      - ###### ステップ実行 
        一行ずつコードを実行し、変数の値の変化を確認できます
         - ###### ステップイン
           関数やプロシージャの中身もステップ実行します
        一行ずつコードを実行し、変数の値の変化を確認できます
         - ###### ステップオーバー
           関数やプロシージャの中身は実行しますが、ステップインしません
        一行ずつコードを実行し、変数の値の変化を確認できます
         - ###### ステップアウト
           現在の関数やプロシージャから抜け出して、呼び出し元の次の行に移動します
     ![stepin.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677000/49afc061-c503-e814-8334-434eb5694657.png)
     実行すると、画像の黄色い矢印の行で処理が止まります。


## おわりに
慣れないVBAの投稿だったため拙い文章になりましたが、最後まで読んで頂きありがとうございました。

## 参考記事
- [Office VBA リファレンス](https://learn.microsoft.com/ja-jp/office/vba/api/overview/)
- [デバッガーのドキュメント - Visual Studio (Windows)](https://learn.microsoft.com/ja-jp/visualstudio/debugger/?view=vs-2022)