Excelで毎月のデータ集計業務を効率化！~ChatGPTで0から始めるVBAコード~

## ChatGPTを使ってVBAコードを作ってもらいました！

![ai_shigoto.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799961/f94718c7-af6e-8cfd-5a5c-e9b864daeba2.png)

VBAをほぼ触ったことのない私が、毎月発生するExcel集計業務をVBAで効率化しました。
どれだけ初心者かといいますと、**ChatGPTにまず質問したことは「Excelでマクロを入力するには」** でした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799961/067d6712-5bc0-5e56-28c6-aa972c918e95.png)

そのレベルからChatGPTは丁寧に説明してくれました。
まずは、Excelの開発ツール設定から入りました笑

質問を繰り返して最終的にできたのは…
<br>
<details><summary> プログラムを開く(折りたたみしています。)</summary>

```
Sub ProcessSheets()
    Dim ws As Worksheet
    Dim wsSeikyu As Worksheet
    Dim wsSeikyuKingaku As Worksheet
    Dim lastRow As Long
    Dim i As Long
    Dim keyword As String
    
    ' シートを設定
    Set ws = ThisWorkbook.Sheets("作業シート")
    Set wsSeikyu = ThisWorkbook.Sheets("請求先")
    Set wsSeikyuKingaku = ThisWorkbook.Sheets("請求金額")
    
    ' 検索キーワード
    keyword = "修正"
    
    ' I列の最終行を取得
    lastRow = ws.Cells(ws.Rows.Count, "I").End(xlUp).Row
    
    ' 最後の行から逆方向にループして、キーワードを含む行を削除
    For i = lastRow To 1 Step -1
        If InStr(ws.Cells(i, "I").Value, keyword) > 0 Then
            ws.Rows(i).Delete
        End If
    Next i

    ' 再度最終行を取得（行削除後の再計算）
    lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
    
    ' A列を「請求先」シートのA列にコピー
    ws.Range("A1:A" & lastRow).Copy Destination:=wsSeikyu.Range("A1")
    
    ' A列を「請求金額」シートのA列にコピー
    ws.Range("A1:A" & lastRow).Copy Destination:=wsSeikyuKingaku.Range("A1")
    
    ' Q列を「請求先」シートのB列にコピー
    ws.Range("Q1:Q" & lastRow).Copy Destination:=wsSeikyu.Range("B1")
    
    ' S列を「請求金額」シートのB列にコピー
    ws.Range("S1:S" & lastRow).Copy Destination:=wsSeikyuKingaku.Range("B1")
    
    ' 「請求先」シートのB列を";"で区切る
    Call SplitColumnByDelimiter(wsSeikyu, "B", ";")
    
    ' 「請求金額」シートのB列を";"で区切る
    Call SplitColumnByDelimiter(wsSeikyuKingaku, "B", ";")
    
    
    ' 後続処理を呼び出し
    
    Call CopyB1ToNonEmptyColumns
    Call CopyB1ToNonEmptyColumns2
    Call InsertAColumnNextNext
    Call InsertAColumnNextNext2
    Call CombineColumns
    Call CombineColumns2
    Call CopyColumnsToPivotData
    
End Sub

Sub SplitColumnByDelimiter(ws As Worksheet, colLetter As String, delimiter As String)
    Dim lastRow As Long
    Dim i As Long
    Dim cellValue As String
    Dim splitValues As Variant
    Dim j As Long
    Dim colNum As Long

    ' 最終行を取得
    lastRow = ws.Cells(ws.Rows.Count, colLetter).End(xlUp).Row
    colNum = Columns(colLetter).Column

    ' 各行のセルの値を分割して新しい列に設定
    For i = 1 To lastRow
        cellValue = ws.Cells(i, colNum).Value
        If cellValue <> "" Then
            splitValues = Split(cellValue, delimiter)
            For j = LBound(splitValues) To UBound(splitValues)
                ws.Cells(i, colNum + j).Value = splitValues(j)
            Next j
        End If
    Next i
End Sub

Sub CopyB1ToNonEmptyColumns()
    Dim ws As Worksheet
    Dim col As Long
    Dim lastRow As Long
    Dim cell As Range
    
    ' シートを設定
    Set ws = ThisWorkbook.Sheets("請求先")
    
    ' B1の値を取得
    Dim b1Value As String
    b1Value = ws.Range("B1").Value
    
    ' C列からT列までループ
    For col = 3 To 20 ' C列は3、T列は20
        ' 最終行を取得
        lastRow = ws.Cells(ws.Rows.Count, col).End(xlUp).Row
        
        ' 列内のセルをループしてNULL（空白）ではないセルを確認
        For Each cell In ws.Range(ws.Cells(1, col), ws.Cells(lastRow, col))
            If cell.Value <> "" Then
                ' 1行目にB1の値をコピー＆ペースト
                ws.Cells(1, col).Value = b1Value
                ' 列内にNULL（空白）でないデータが1つでもあれば次の列に進む
                Exit For
            End If
        Next cell
    Next col
End Sub

Sub CopyB1ToNonEmptyColumns2()
    Dim ws As Worksheet
    Dim col As Long
    Dim lastRow As Long
    Dim cell As Range
    
    ' シートを設定
    Set ws = ThisWorkbook.Sheets("請求金額")
    
    ' B1の値を取得
    Dim b1Value As String
    b1Value = ws.Range("B1").Value
    
    ' C列からT列までループ
    For col = 3 To 20 ' C列は3、T列は20
        ' 最終行を取得
        lastRow = ws.Cells(ws.Rows.Count, col).End(xlUp).Row
        
        ' 列内のセルをループしてNULL（空白）ではないセルを確認
        For Each cell In ws.Range(ws.Cells(1, col), ws.Cells(lastRow, col))
            If cell.Value <> "" Then
                ' 1行目にB1の値をコピー＆ペースト
                ws.Cells(1, col).Value = b1Value
                ' 列内にNULL（空白）でないデータが1つでもあれば次の列に進む
                Exit For
            End If
        Next cell
    Next col
End Sub

Sub InsertAColumnNextNext()
    Dim ws As Worksheet
    Dim currentCol As Long
    Dim lastCol As Long
    
    ' シートを設定
    Set ws = ThisWorkbook.Sheets("請求先")
    
    ' 最初の挿入位置はB列の次の列（C列）
    currentCol = 3 ' C列
    
    ' 最終列を取得
    lastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
    
    ' 挿入処理を繰り返す
    Do While currentCol <= lastCol + 1
        ' A列のデータをコピー
        ws.Columns("A").Copy
        
        ' 現在の位置にA列のコピーを挿入
        ws.Columns(currentCol).Insert Shift:=xlToRight
        ws.Columns(currentCol).PasteSpecial Paste:=xlPasteValues
        Application.CutCopyMode = False
        
        ' 挿入位置を次の次の列に設定
        currentCol = currentCol + 2
        
        ' 挿入後の最終列を再取得
        lastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
    Loop
End Sub

Sub InsertAColumnNextNext2()
    Dim ws As Worksheet
    Dim currentCol As Long
    Dim lastCol As Long
    
    ' シートを設定
    Set ws = ThisWorkbook.Sheets("請求金額")
    
    ' 最初の挿入位置はB列の次の列（C列）
    currentCol = 3 ' C列
    
    ' 最終列を取得
    lastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
    
    ' 挿入処理を繰り返す
    Do While currentCol <= lastCol + 1
        ' A列のデータをコピー
        ws.Columns("A").Copy
        
        ' 現在の位置にA列のコピーを挿入
        ws.Columns(currentCol).Insert Shift:=xlToRight
        ws.Columns(currentCol).PasteSpecial Paste:=xlPasteValues
        Application.CutCopyMode = False
        
        ' 挿入位置を次の次の列に設定
        currentCol = currentCol + 2
        
        ' 挿入後の最終列を再取得
        lastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
    Loop
End Sub

Sub CombineColumns()
    Dim ws As Worksheet
    Dim lastRowAB As Long
    Dim lastRow As Long
    Dim startRow As Long
    Dim i As Long
    Dim currentCol As Long
    
    ' シートを設定
    Set ws = ThisWorkbook.Sheets("請求先")
    
    ' AB列の最後の行を取得
    lastRowAB = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
    
    ' データをまとめる開始行を設定（AB列の最後の行の次の行）
    startRow = lastRowAB + 1
    
    ' 列の初期設定（CD列から開始）
    currentCol = 3 ' C列
    
    ' データがなくなるまで2列ずつ処理
    Do While ws.Cells(1, currentCol).Value <> "" Or ws.Cells(2, currentCol).Value <> ""
        ' 処理する列の最終行を取得
        lastRow = ws.Cells(ws.Rows.Count, currentCol).End(xlUp).Row
        
        ' 2列分のデータをAB列の次に追加
        For i = 1 To lastRow
            ws.Cells(startRow + i - 1, 1).Value = ws.Cells(i, currentCol).Value ' 現在の列をA列に
            ws.Cells(startRow + i - 1, 2).Value = ws.Cells(i, currentCol + 1).Value ' 次の列をB列に
        Next i
        
        ' データを追加した後の最後の行を再計算
        startRow = startRow + lastRow
        
        ' 次の2列に移動
        currentCol = currentCol + 2
    Loop
    
    ' C列以降のデータを削除
    ws.Range(ws.Cells(1, 3), ws.Cells(ws.Rows.Count, ws.Columns.Count)).ClearContents
End Sub

Sub CombineColumns2()
    Dim ws As Worksheet
    Dim lastRowAB As Long
    Dim lastRow As Long
    Dim startRow As Long
    Dim i As Long
    Dim currentCol As Long
    
    ' シートを設定
    Set ws = ThisWorkbook.Sheets("請求金額")
    
    ' AB列の最後の行を取得
    lastRowAB = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
    
    ' データをまとめる開始行を設定（AB列の最後の行の次の行）
    startRow = lastRowAB + 1
    
    ' 列の初期設定（CD列から開始）
    currentCol = 3 ' C列
    
    ' データがなくなるまで2列ずつ処理
    Do While ws.Cells(1, currentCol).Value <> "" Or ws.Cells(2, currentCol).Value <> ""
        ' 処理する列の最終行を取得
        lastRow = ws.Cells(ws.Rows.Count, currentCol).End(xlUp).Row
        
        ' 2列分のデータをAB列の次に追加
        For i = 1 To lastRow
            ws.Cells(startRow + i - 1, 1).Value = ws.Cells(i, currentCol).Value ' 現在の列をA列に
            ws.Cells(startRow + i - 1, 2).Value = ws.Cells(i, currentCol + 1).Value ' 次の列をB列に
        Next i
        
        ' データを追加した後の最後の行を再計算
        startRow = startRow + lastRow
        
        ' 次の2列に移動
        currentCol = currentCol + 2
    Loop
    
    ' C列以降のデータを削除
    ws.Range(ws.Cells(1, 3), ws.Cells(ws.Rows.Count, ws.Columns.Count)).ClearContents
End Sub

Sub CopyColumnsToPivotData()
    Dim wsSeikyu As Worksheet
    Dim wsSeikyuKingaku As Worksheet
    Dim wsPivotData As Worksheet
    Dim lastRowSeikyu As Long
    Dim lastRowSeikyuKingaku As Long
    
    ' シートを設定
    Set wsSeikyu = ThisWorkbook.Sheets("請求先")
    Set wsSeikyuKingaku = ThisWorkbook.Sheets("請求金額")
    Set wsPivotData = ThisWorkbook.Sheets("ピポット用データ")
    
    ' 請求先シートのAB列の最終行を取得
    lastRowSeikyu = wsSeikyu.Cells(wsSeikyu.Rows.Count, "A").End(xlUp).Row
    
    ' 請求先シートのAB列をピポット用データシートのAB列にコピー
    wsSeikyu.Range("A1:B" & lastRowSeikyu).Copy Destination:=wsPivotData.Range("A1")
    
    ' 請求金額シートのB列の最終行を取得
    lastRowSeikyuKingaku = wsSeikyuKingaku.Cells(wsSeikyuKingaku.Rows.Count, "B").End(xlUp).Row
    
    ' 請求金額シートのC列をピポット用データシートのC列にコピー
    wsSeikyuKingaku.Range("B1:B" & lastRowSeikyuKingaku).Copy Destination:=wsPivotData.Range("C1")
End Sub
```
</details>
<br>
もう少しシンプルなコーディングができたかもしれませんが、
0から作ったわりにうまくできたと思います。(自画自賛)



## 今回作成したもの
今回作成したツールは、**他システムから出した請求データを使って、請求先と金額を算出する** というツールです。
<br>
「Excel関数でよくない？」
<br><br>

そうです、請求先カラムと請求金額カラムがあり、
1:1の関係であればsumif関数とかVlook関数とかでいいんですが、
今回は1カラムに複数請求先/請求金額が入っておりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799961/df55c782-e7df-7690-aaf6-f9c62424b294.png)

決裁単位で請求が発生するため、複数請求先、金額が発生するシステムでした。
元となるシステムの開発費や改修による影響が高いため、
カラム数を変えず1カラムで複数データを扱うことはたまに見かけます。
~~Excel関数で集計できたらやり方教えてください~~

従来では区切り位置の調整を行い、カラムを整えて集約しておりました。
この作業に時間がかかったので、マクロ実行するとこのような集計ができるようになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799961/eb91ce18-bf03-197c-5bea-70c85b6380c1.png)
※説明のため、ダミーデータかつ、必要ないカラムは削除しています。

削減効果は30分～1時間/月の作業を、、、
**20秒/月に削減しました！！**



## 使用したツール
使用したツールは下記2つだけです。

・[ChatGPT](https://chatgpt.com/)
・Excel


## 作成手順
前段触れたように、
**①ChatGPTに要件を説明**
**②コーディングしてもらう**
**③ExcelのVBAエディターに貼り実行する**
**④エラー等調整する**
上記のように部分部分で機能を開発して、最後に繋げました。

**具体的に下記のような依頼をしました。**
※細かい要件、エラー修正などは含みません

:::note info
下記要件を実現するExcelのVBAコードをおしえてください。
"作業シート"のI列に"修正"が含まれる列を削除する。
"作業シート"A列を"請求先"のA列にコピーする。
"作業シート"A列を"請求金額"のA列にコピーする。
"作業シート"Q列を"請求先"のB列にコピーする。
"作業シート"S列を"請求金額"のB列にコピーする。
"請求先"のB列にExcel操作でデータ>区切り位置>コンマやタブなどの区切り文字によってフィールドごとに区切られたデータ>その他";"を使って;でカラムを区切る。
"請求金額"のB列にExcel操作でデータ>区切り位置>コンマやタブなどの区切り文字によってフィールドごとに区切られたデータ>その他";"を使って;でカラムを区切る。
:::

:::note info
下記要件を実現するExcelのVBAコードをおしえてください。
"請求書"のC列にNULLじゃないデータがあれば1行目にB1の値をコピー＆ペーストする。
以降D列～T列まで同様の処理を行う
:::

:::note info
下記要件を実現するExcelのVBAコードをおしえてください。
"請求先"のA列の次の列がある場合、A列をコピーし次の次の列にコピーした列の挿入をする。
挿入した列に次の列がある場合、A列をコピーし次の次の列にコピーした列の挿入をする。
以後、次に列があるまで連続する。
:::

:::note info
下記要件を実現するExcelのVBAコードをおしえてください。
"請求先"をAB列の2行にまとめたいです。
例：
AB列の最後の列の次の列からCD列の1行目から最後の行までをもってきて、
また、AB列の最後の列の次の列からEF列の1行目から最後の行までをもってくる。
以後、次に列がなくなるまで連続する。
:::

:::note info
下記要件を実現するExcelのVBAコードをおしえてください。
"請求先"のAB列を"ピポット用データ"のAB列にコピーしてください。
"請求金額"のB列を"ピポット用データ"のC列にコピーしてください。
:::

:::note info
ExcelのVBAコードにおいて下記を1度に連続で実行する方法をおしえてください。
Sub ProcessSheets()
Sub SplitColumnByDelimiter(ws As Worksheet, colLetter As String, delimiter As String)
Sub CopyB1ToNonEmptyColumns()
Sub CopyB1ToNonEmptyColumns2()
Sub InsertAColumnNextNext()
Sub InsertAColumnNextNext2()
Sub CombineColumns()
Sub CombineColumns2()
Sub CopyColumnsToPivotData()
:::

修正・調整については下記のように対応いたしました。

:::note alert
エラーが発生した場合
⇒エラー文章をそのまま送り、
　ChatGPTに修正依頼をしました。
:::

:::note alert
思うような動作がされないとき
⇒現在どういう動作をしているか、自分の想定とのギャップをChatGPTに伝え、
　修正依頼をしました。
⇒要件をもう少し具体的・詳細に記載し再度依頼をかけました。

:::

:::note alert
うまく伝わらない
⇒私の場合は「;」でカラムを区切る部分がうまく伝わらなかったです。
　当初は、『「;」で区切り、カラムを分ける』や、『「A;B」を;で区切り「A」と「B」でカラム分けする』など要望したが伝わりませんでした。

 そのため、実際のExcel操作（このボタンを押す）などの伝え方を行ったら、良いコードが出てきました。
 伝え方の工夫をしてみてください。

:::

## 反省/まとめ
VBAを最初から学ぶのであれば、数週間～数か月時間がかかりますが、AIを使うと0から作れることが分かりました。
その時間で他の業務を行ったり、業務改善に時間を当てられました。
また、コードを見ること、要件をまとめることで学習にもいいと感じました。
~~英語の勉強で文法を飛ばして英会話しちゃう感覚？~~

反省点としては
**「なぜChatGPTをもっと早く使わなかったのだ」**
これにつきます。
正確な数字報告などが求められる場面など、使わない方がいいところはありますが、
非常に頼りになるツールだと感じました。