1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CodePen ×AI ×VBAで自分の業務改善

1
Posted at

はじめに

こちらの記事は先回の記事の続きとなっています。

先回の記事はこちら
https://x.com/to_nakagawa/status/2064705380475945260?s=20

先回作成したHTMLコードで作成したアプリを
実務で使用しているExcelファイルに反映し、
同僚に使用、改善を進めていきました。

以下、作成したサンプル表の動画になります。

用意するもの
CodePen(コードペン)https://codepen.io/
ChatGPT(その他Gemini、 Copilot、などAI)https://chatgpt.com/ja-JP/
EXCEL(皆さんご存じマイクロソフト社表計算ソフト) https://www.microsoft.com/ja-jp/download

AIでVBAコードを作成
まずはChatGPTにサンプルファイルをコピーして共有します。
共有した上で依頼をしました。
image.png

そこで答えてくれたコードをVBAに入力をします。
返答コードはこちら

振分数量反映ボタンと数値の反映 Option Explicit

'------------------------------------------------------------
' 初回のみ実行:第1・2シートに「振分数量を反映」ボタンを作成します
'------------------------------------------------------------
Public Sub 第12シートにボタン作成()

Dim ws As Worksheet
Dim btn As Button
Dim shp As Shape

Set ws = ThisWorkbook.Worksheets("第1・2")

'同じボタンが既にある場合は削除して作り直す
For Each shp In ws.Shapes
    If shp.Name = "btnSheet2QtyReflect" Then
        shp.Delete
        Exit For
    End If
Next shp

'表の右側にボタンを配置
Set btn = ws.Buttons.Add( _
    Left:=ws.Range("V1").Left, _
    Top:=ws.Range("V1").Top, _
    Width:=150, _
    Height:=32)
    
With btn
    .Name = "btnSheet2QtyReflect"
    .Caption = "振分数量を反映"
    .OnAction = "Sheet2振分数量反映"
End With

MsgBox "第1・2シートにボタンを作成しました。", vbInformation

End Sub

'------------------------------------------------------------
' Sheet2の振分数量を、商品名・店舗名を参照して第1・2シートへ反映
'
' Sheet2想定:
' B1:商品名
' A列:店舗名
' E列:振分数量
'
' 第1・2シート想定:
' G列:商品名
' 11行目:店舗名見出し
' 商品名行 × 店舗名列 の交点に振分数量を反映
'------------------------------------------------------------
Public Sub Sheet2振分数量反映()

Dim wsPlan As Worksheet
Dim wsData As Worksheet
Dim productName As String
Dim productCell As Range
Dim storeCell As Range
Dim lastSrcRow As Long
Dim r As Long
Dim storeName As String
Dim qty As Variant
Dim updateCount As Long
Dim missingStores As String

On Error GoTo ErrHandler

Application.ScreenUpdating = False
Application.EnableEvents = False

Set wsPlan = ThisWorkbook.Worksheets("第1・2")
Set wsData = ThisWorkbook.Worksheets("Sheet2")

productName = Trim(CStr(wsData.Range("B1").Value))

If productName = "" Then
    MsgBox "Sheet2のB1に商品名がありません。", vbExclamation
    GoTo ExitHandler
End If

'第1・2シートのG列から商品名を完全一致で検索
Set productCell = wsPlan.Columns("G").Find( _
    What:=productName, _
    LookIn:=xlValues, _
    LookAt:=xlWhole, _
    MatchCase:=False)
    
If productCell Is Nothing Then
    MsgBox "第1・2シートのG列に商品名「" & productName & "」が見つかりません。", vbExclamation
    GoTo ExitHandler
End If

lastSrcRow = wsData.Cells(wsData.Rows.Count, "A").End(xlUp).Row

If lastSrcRow < 3 Then
    MsgBox "Sheet2に反映対象データがありません。", vbExclamation
    GoTo ExitHandler
End If

For r = 3 To lastSrcRow

    storeName = Trim(CStr(wsData.Cells(r, "A").Value))
    qty = wsData.Cells(r, "E").Value
    
    If storeName <> "" Then
    
        '第1・2シートの11行目から店舗名を完全一致で検索
        Set storeCell = wsPlan.Rows(11).Find( _
            What:=storeName, _
            LookIn:=xlValues, _
            LookAt:=xlWhole, _
            MatchCase:=False)
        
        If storeCell Is Nothing Then
            missingStores = missingStores & vbCrLf & "・" & storeName
        Else
            wsPlan.Cells(productCell.Row, storeCell.Column).Value = qty
            updateCount = updateCount + 1
        End If
        
    End If
    
Next r

If missingStores <> "" Then
    MsgBox "反映完了:" & updateCount & "件" & vbCrLf & vbCrLf & _
           "ただし、以下の店舗名は第1・2シートの11行目に見つかりませんでした。" & _
           missingStores, vbExclamation
Else
    MsgBox "反映完了:" & updateCount & "件" & vbCrLf & _
           "商品名「" & productName & "」の振分数量を第1・2シートに反映しました。", vbInformation
End If

ExitHandler:
Application.EnableEvents = True
Application.ScreenUpdating = True
Exit Sub

ErrHandler:
MsgBox "エラーが発生しました。" & vbCrLf & Err.Description, vbCritical
Resume ExitHandler

End Sub

開発タグからVisual Basicを起動。
すると次のような画面になります。
image.png

ここから先、どうすれば?と思ったことも
ChatGPTに相談すれば答えてくれました。
・挿入タグの標準モジュールを開き、コード出てきたウインドウにコードを貼り付け

image.png

・貼り付け後ファイルを保存
image.png

・続いて実行します。
image.png

するとウィンドウが表示されるので項目を選択して実行をします。
まずは、反映ボタンを作成したかったので、ボタン作成から。
image.png

続いて、Sheet2振分数量反映も実行すると希望通りに表に数値が反映されました!

image.png

しかし、りんごだけではなく、バナナも表に反映させたいので、CodePenで作成した数値を「Sheet3」に貼り付けし、新たに加えたsheetも参照するように、新たにVBAコードの作成を依頼。
image.png

Sheet追加時も同様に処理 作成されたコードはこちら Option Explicit

'============================================================
' 同形式の振分シートをまとめて「第1・2」シートへ反映するマクロ
'
' 反映元シートの想定:
' A1:商品名
' B1:商品名の値
' A2:店舗名
' E2:振分数量
' A3以降:店舗名
' E3以降:振分数量
'
' 反映先「第1・2」シートの想定:
' G列:商品名
' 11行目:店舗名見出し
' 商品名行 × 店舗名列 の交点に振分数量を反映
'============================================================

Private Const PLAN_SHEET_NAME As String = "第1・2"
Private Const PRODUCT_COL As String = "G"
Private Const STORE_HEADER_ROW As Long = 11
Private Const SRC_PRODUCT_CELL As String = "B1"
Private Const SRC_STORE_COL As String = "A"
Private Const SRC_QTY_COL As String = "E"
Private Const SRC_START_ROW As Long = 3

'------------------------------------------------------------
' 初回のみ実行:第1・2シートにボタンを作成します
'------------------------------------------------------------
Public Sub 第12シートに全Sheet反映ボタン作成()

Dim ws As Worksheet
Dim btn As Button
Dim shp As Shape

Set ws = ThisWorkbook.Worksheets(PLAN_SHEET_NAME)

'同じボタンが既にある場合は削除して作り直す
For Each shp In ws.Shapes
    If shp.Name = "btnAllDistributionReflect" Then
        shp.Delete
        Exit For
    End If
Next shp

Set btn = ws.Buttons.Add( _
    Left:=ws.Range("V1").Left, _
    Top:=ws.Range("V1").Top, _
    Width:=170, _
    Height:=34)

With btn
    .Name = "btnAllDistributionReflect"
    .Caption = "全振分Sheetを反映"
    .OnAction = "全振分Sheetを反映"
End With

MsgBox "第1・2シートにボタンを作成しました。", vbInformation

End Sub

'------------------------------------------------------------
' Sheet2、Sheet3など、振分形式のシートをすべて反映します
'------------------------------------------------------------
Public Sub 全振分Sheetを反映()

Dim wsPlan As Worksheet
Dim wsSrc As Worksheet
Dim targetSheetCount As Long
Dim updateCount As Long
Dim missingProducts As String
Dim missingStores As String
Dim skippedSheets As String

On Error GoTo ErrHandler

Application.ScreenUpdating = False
Application.EnableEvents = False

Set wsPlan = ThisWorkbook.Worksheets(PLAN_SHEET_NAME)

For Each wsSrc In ThisWorkbook.Worksheets

    If IsDistributionSheet(wsSrc) Then
        targetSheetCount = targetSheetCount + 1

        ReflectOneDistributionSheet _
            wsPlan:=wsPlan, _
            wsSrc:=wsSrc, _
            updateCount:=updateCount, _
            missingProducts:=missingProducts, _
            missingStores:=missingStores
    Else
        If wsSrc.Name <> PLAN_SHEET_NAME Then
            skippedSheets = skippedSheets & vbCrLf & "・" & wsSrc.Name
        End If
    End If

Next wsSrc

If targetSheetCount = 0 Then
    MsgBox "反映対象の振分シートが見つかりませんでした。" & vbCrLf & _
           "A1が「商品名」、A2が「店舗名」、E2が「振分数量」のシートを対象にします。", vbExclamation
    GoTo ExitHandler
End If

Dim msg As String
msg = "反映処理が完了しました。" & vbCrLf & vbCrLf & _
      "対象シート数:" & targetSheetCount & "件" & vbCrLf & _
      "反映件数:" & updateCount & "件"

If missingProducts <> "" Then
    msg = msg & vbCrLf & vbCrLf & _
          "【第1・2シートのG列に商品名が見つからなかったもの】" & _
          missingProducts
End If

If missingStores <> "" Then
    msg = msg & vbCrLf & vbCrLf & _
          "【第1・2シートの11行目に店舗名が見つからなかったもの】" & _
          missingStores
End If

MsgBox msg, vbInformation

ExitHandler:
Application.EnableEvents = True
Application.ScreenUpdating = True
Exit Sub

ErrHandler:
MsgBox "エラーが発生しました。" & vbCrLf & Err.Description, vbCritical
Resume ExitHandler

End Sub

'------------------------------------------------------------
' 1つの振分シートを第1・2シートに反映
'------------------------------------------------------------
Private Sub ReflectOneDistributionSheet( _
ByVal wsPlan As Worksheet, _
ByVal wsSrc As Worksheet, _
ByRef updateCount As Long, _
ByRef missingProducts As String, _
ByRef missingStores As String)

Dim productName As String
Dim productCell As Range
Dim storeCell As Range
Dim lastSrcRow As Long
Dim r As Long
Dim storeName As String
Dim qty As Variant

productName = Trim(CStr(wsSrc.Range(SRC_PRODUCT_CELL).Value))

If productName = "" Then Exit Sub

Set productCell = wsPlan.Columns(PRODUCT_COL).Find( _
    What:=productName, _
    LookIn:=xlValues, _
    LookAt:=xlWhole, _
    MatchCase:=False)

If productCell Is Nothing Then
    missingProducts = missingProducts & vbCrLf & "・" & wsSrc.Name & ":" & productName
    Exit Sub
End If

lastSrcRow = wsSrc.Cells(wsSrc.Rows.Count, SRC_STORE_COL).End(xlUp).Row

If lastSrcRow < SRC_START_ROW Then Exit Sub

For r = SRC_START_ROW To lastSrcRow

    storeName = Trim(CStr(wsSrc.Cells(r, SRC_STORE_COL).Value))
    qty = wsSrc.Cells(r, SRC_QTY_COL).Value

    If storeName <> "" Then

        Set storeCell = wsPlan.Rows(STORE_HEADER_ROW).Find( _
            What:=storeName, _
            LookIn:=xlValues, _
            LookAt:=xlWhole, _
            MatchCase:=False)

        If storeCell Is Nothing Then
            missingStores = missingStores & vbCrLf & "・" & wsSrc.Name & " / " & productName & " / " & storeName
        Else
            wsPlan.Cells(productCell.Row, storeCell.Column).Value = qty
            updateCount = updateCount + 1
        End If

    End If

Next r

End Sub

'------------------------------------------------------------
' 振分シートかどうかを自動判定
' シート名ではなく、見出しで判定するため、Sheet4以降でも対応可能
'------------------------------------------------------------
Private Function IsDistributionSheet(ByVal ws As Worksheet) As Boolean

If ws.Name = PLAN_SHEET_NAME Then
    IsDistributionSheet = False
    Exit Function
End If

If Trim(CStr(ws.Range("A1").Value)) = "商品名" _
   And Trim(CStr(ws.Range("A2").Value)) = "店舗名" _
   And Trim(CStr(ws.Range("E2").Value)) = "振分数量" Then
    IsDistributionSheet = True
Else
    IsDistributionSheet = False
End If

End Function

コードの中身を理解していないため、先ほどのコードと別でモジュール作る?先ほどのモジュールを削除する?分からなかった為、ChatGPTに確認したところ、「基本的には先ほどのコードを削除して、今回のコードで上書き」と教えてくれました。
そのとおりにすすめて、実行したら、期待通りの反映がされました!
image.png

しかし、何かおかしい、フォントが揃っていないことに違和感。

こちらも機能を追加してフォントの統一も備えることができました。

フォント統一追加コード Public Sub 全シートフォントをMeiryoUIに統一()
Dim ws As Worksheet
Dim shp As Shape

For Each ws In ThisWorkbook.Worksheets

    'シート内のすべてのセルをMeiryo UIにする
    ws.Cells.Font.Name = FIXED_FONT_NAME

    '図形・ボタン・テキストボックスなどもMeiryo UIにする
    For Each shp In ws.Shapes
        On Error Resume Next

        If shp.TextFrame2.HasText Then
            shp.TextFrame2.TextRange.Font.Name = FIXED_FONT_NAME
        End If

        If shp.TextFrame.Characters.Count > 0 Then
            shp.TextFrame.Characters.Font.Name = FIXED_FONT_NAME
        End If

        On Error GoTo 0
    Next shp

Next ws

image.png

サンプル表はここで終了で、実際に使用している表に同じ機能を実装します。
100店舗以上の為、表の配置がサンプルとは違います。
配置をChatGPTに伝えて再度コード作成する必要がありました。
image.png

調整をすることで店舗数に合わせた運用をすることができました!

同僚に機能を説明して、使ってみてもらいました。
B😁 「なんか便利そうだね、使えそうだけど、関数でよくない?」
私😭「私も関数を普段使っているので分かりますけれど、誤って関数消してしまったりと不便なこともありますよね!」
B😁 「まあそうだなー、使ってみるよ、ありがとう」
私😊「こちらこそありがとうございます!直した方が良いところ、教えてください」
B😁 「了解」

まとめ
Bさんにまだ感想をお聞きできていないですが、自分の中ではまだまだ改善の余地があります。作成したファイルの貼り付けを簡略化する方法があると思うので、改善します。

また、全店舗を一枚にするのではなく、1店舗で1枚にまとめると、店舗担当者の方は見やすいと感じます。次回そこにも着手していきます。

最後まで読んでいただいて、ありがとうございました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?