目次
前回コードの問題点
前回は
- 階層連動
- 条件付きユニーク化
- 結合条件での抽出
ここまで完成しました。
正直、この時点で「動く仕組み」はできています。
ただし、実務ではここで必ず問題が出ます。
それが 列に依存しすぎている です。
例えば今回のコードは
- D列=調査票名
- E列=項目名
- F列=品目名
- G列=アイテム名
と「固定」されています。
一見問題なさそうですが、実務ではこうなります。
- 列の順番が変わる
- 新しい列が追加される
- レイアウトが変更される
この瞬間に、全部壊れます。これが現場で一番多いトラブルです。
なので今回は 列番号を動的に管理 していきます。

今回取り扱うデータも経済産業省の公開データ「生産動態統計年報(2024年)」です。
今回やること
やることはシンプルです。
- Dictionaryで項目名 → 列番号を管理
- 列番号のハードコーディングを廃止
- 可読性を維持したまま柔軟化
この一手で「壊れにくいコード」になります。
実際のCopilotとのやり取り
利用者 → Copilot
既存の階層連動コンボボックスのコードを改善してください。 ■修正内容
・列番号(D,E,F,G)を固定せず、項目名から動的に取得する
・1行目のヘッダーから列番号を特定する
・Dictionaryで「項目名 → 列番号」を管理
・既存のロジック(階層連動・ユニーク化)は維持 ■対象項目
・調査票名
・項目名
・品目名
・アイテム名 ■その他
・可読性重視でコメント付き
・コードは省略せず全文提示
Copilot → 利用者
以下に、列番号を動的に管理するよう改善した完全版コードを提示します。
Option Explicit
'---------------------------------------------
' 列名 → 列番号 を保持する Dictionary
'---------------------------------------------
Private ColIndex As Object 'Dictionary
'---------------------------------------------
' フォーム初期化:列番号取得 → 調査票名のみロード
'---------------------------------------------
Private Sub UserForm_Initialize()
'列番号をヘッダーから取得
Set ColIndex = CreateObject("Scripting.Dictionary")
Call InitColumnIndex
'最上位の調査票名をロード
Load調査票名
End Sub
'---------------------------------------------
' ヘッダー行(1行目)から列番号を取得
'---------------------------------------------
Private Sub InitColumnIndex()
Dim ws As Worksheet
Dim lastCol As Long
Dim i As Long
Dim header As String
Set ws = ThisWorkbook.Worksheets("data")
lastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
'1行目のヘッダーを走査して Dictionary に登録
For i = 1 To lastCol
header = Trim(ws.Cells(1, i).Value)
If header <> "" Then
If Not ColIndex.Exists(header) Then
ColIndex.Add header, i
End If
End If
Next i
End Sub
'---------------------------------------------
' 調査票名変更 → 項目名を再ロード
'---------------------------------------------
Private Sub cmb調査票名_Change()
cmb項目名.Clear
cmb品目名.Clear
cmbアイテム名.Clear
If cmb調査票名.ListIndex >= 0 Then
Load項目名 cmb調査票名.Value
End If
End Sub
'---------------------------------------------
' 項目名変更 → 品目名を再ロード
'---------------------------------------------
Private Sub cmb項目名_Change()
cmb品目名.Clear
cmbアイテム名.Clear
If cmb調査票名.ListIndex >= 0 And cmb項目名.ListIndex >= 0 Then
Load品目名 cmb調査票名.Value, cmb項目名.Value
End If
End Sub
'---------------------------------------------
' 品目名変更 → アイテム名を再ロード
'---------------------------------------------
Private Sub cmb品目名_Change()
cmbアイテム名.Clear
If cmb調査票名.ListIndex >= 0 _
And cmb項目名.ListIndex >= 0 _
And cmb品目名.ListIndex >= 0 Then
Loadアイテム名 cmb調査票名.Value, cmb項目名.Value, cmb品目名.Value
End If
End Sub
'===========================================================
' 調査票名のロード(最上位)
'===========================================================
Private Sub Load調査票名()
Dim ws As Worksheet
Dim lastRow As Long
Dim dic As Object
Dim i As Long
Dim col調査票 As Long
Dim val As String
Set ws = ThisWorkbook.Worksheets("data")
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Set dic = CreateObject("Scripting.Dictionary")
'列番号を Dictionary から取得
col調査票 = ColIndex("調査票名")
'調査票名をユニーク化
For i = 2 To lastRow
val = Trim(ws.Cells(i, col調査票).Value)
If val <> "" Then
If Not dic.Exists(val) Then dic.Add val, True
End If
Next i
cmb調査票名.List = dic.Keys
End Sub
'===========================================================
' 項目名のロード(調査票名 → 項目名)
'===========================================================
Private Sub Load項目名(ByVal 調査票 As String)
Dim ws As Worksheet
Dim lastRow As Long
Dim dic As Object
Dim i As Long
Dim col調査票 As Long, col項目 As Long
Dim val As String
Set ws = ThisWorkbook.Worksheets("data")
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Set dic = CreateObject("Scripting.Dictionary")
col調査票 = ColIndex("調査票名")
col項目 = ColIndex("項目名")
For i = 2 To lastRow
If Trim(ws.Cells(i, col調査票).Value) = 調査票 Then
val = Trim(ws.Cells(i, col項目).Value)
If val <> "" Then
If Not dic.Exists(val) Then dic.Add val, True
End If
End If
Next i
cmb項目名.List = dic.Keys
End Sub
'===========================================================
' 品目名のロード(調査票名 × 項目名 → 品目名)
'===========================================================
Private Sub Load品目名(ByVal 調査票 As String, ByVal 項目 As String)
Dim ws As Worksheet
Dim lastRow As Long
Dim dic As Object
Dim i As Long
Dim col調査票 As Long, col項目 As Long, col品目 As Long
Dim val As String
Set ws = ThisWorkbook.Worksheets("data")
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Set dic = CreateObject("Scripting.Dictionary")
col調査票 = ColIndex("調査票名")
col項目 = ColIndex("項目名")
col品目 = ColIndex("品目名")
For i = 2 To lastRow
If Trim(ws.Cells(i, col調査票).Value) = 調査票 _
And Trim(ws.Cells(i, col項目).Value) = 項目 Then
val = Trim(ws.Cells(i, col品目).Value)
If val <> "" Then
If Not dic.Exists(val) Then dic.Add val, True
End If
End If
Next i
cmb品目名.List = dic.Keys
End Sub
'===========================================================
' アイテム名のロード(調査票名 × 項目名 × 品目名 → アイテム名)
'===========================================================
Private Sub Loadアイテム名(ByVal 調査票 As String, _
ByVal 項目 As String, _
ByVal 品目 As String)
Dim ws As Worksheet
Dim lastRow As Long
Dim dic As Object
Dim i As Long
Dim col調査票 As Long, col項目 As Long, col品目 As Long, colアイテム As Long
Dim val As String
Set ws = ThisWorkbook.Worksheets("data")
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Set dic = CreateObject("Scripting.Dictionary")
col調査票 = ColIndex("調査票名")
col項目 = ColIndex("項目名")
col品目 = ColIndex("品目名")
colアイテム = ColIndex("アイテム名")
For i = 2 To lastRow
If Trim(ws.Cells(i, col調査票).Value) = 調査票 _
And Trim(ws.Cells(i, col項目).Value) = 項目 _
And Trim(ws.Cells(i, col品目).Value) = 品目 Then
val = Trim(ws.Cells(i, colアイテム).Value)
If val <> "" Then
If Not dic.Exists(val) Then dic.Add val, True
End If
End If
Next i
cmbアイテム名.List = dic.Keys
End Sub
この修正の本質
ここが一番重要です。
今回の本質は、列依存を排除したです。
今までは「ws.Cells(i, “D”)」のように書いていました。
これは「列が固定されている前提」です。
今回からは「colMap(“調査票名”)」
つまり、意味で列を取得しています。
これにより
- 列が移動しても壊れない
- 列が追加されても対応できる
- メンテナンスが圧倒的に楽
になります。
なぜDictionaryを使うのか
ここも重要です。
Dictionaryは
- キーで高速アクセスできる
- 構造がシンプル
- 拡張しやすい
今回のように 項目名 → 列番号 の管理には最適です。
実務では「名前で管理する」これが基本です。
実務でのインパクト
この修正、かなり効きます。
- Excelレイアウト変更に強くなる
- 修正コストが激減する
- 他の人が見ても理解しやすい
そして何より「長く使えるコードになる」ここが大きいです。
次回やること
次回以降
- 並び順の統一
- UI改善(選択してください)
- 高速化(配列化)
を追加していきます。
ここまでやると、完全に業務アプリレベルになります。
まとめ
今回は 列番号の動的管理 を追加しました。
やっていることはシンプルですが、実務ではかなり重要な改善です。
Excelは、構造が変わる前提で作る必要があります。
今回のように、列を「番号」ではなく「意味」で扱う。
これができるようになると、一気に実務レベルに入ります。
そして今回もポイントは同じです。
自分でコードを書いていない
- 仕様を整理
- プロンプトを書く
これだけです。
ただし、ここからは「改善力」が求められます。
リンク
ChatGPTでExcel VBAマクロを自動生成してみた|初心者でも使える実践手順
Excel VBAのエラー修正をChatGPTに頼んだら原因が一発で分かった話
仕様が曖昧でもOK?ChatGPTにExcel VBAを作らせてみた結果
ChatGPTに作らせたExcel VBAコードは安全?使う前に確認すべきポイント
Excel VBA初心者がChatGPTを使うと挫折しにくくなる理由
CopilotでExcel作業はどこまで効率化できる?実務で使ってみた結果
Copilotに仕事を任せてみた|メール・資料作成はここまで楽になる
Copilotが向いている人・向いていない人を実体験から整理してみた
ChatGPT・Copilot・Geminiに同じ仕事を頼んだら結果が全然違った
結局どれを使えばいい?目的別に生成AIを整理してみた【初心者向け】
初心者が最初にやるべき生成AI活用① ChatGPTで「長文を理解・整理する」読むのがしんどい人ほど効果が出る使い方
初心者が最初にやるべき生成AI活用②ChatGPTに「分からないことをそのまま相談する」使い方・聞き方を気にしない安心感
初心者が最初にやるべき生成AI活用③AIを「自分専用の調べ物係」にする使い方|検索に疲れた人ほど効果が出る
ChatGPTにブログ記事を“赤ペン先生”してもらったら修正力がすごかった話―書くのが苦手な人ほど使ってほしい文章改善―
CopilotでExcel作業手順書を一瞬で作る|引き継ぎ資料が秒で完成した話
Geminiでアイデアが枯れたときの発想復活法|何も思いつかないを脱出する使い方
ChatGPT・Copilot・Geminiをブレスト役で使い分ける実例|発想が加速した方法
CopilotでExcel集計→Word報告書を一気に作る実務フロー― 月次報告が“考えずに終わる”ようになった話 ―
Copilotで会議議事録からToDo管理まで一気にやってみた実務フロー
Geminiで社内資料の画像を作ってみた|伝わらない資料が一瞬で変わった話
ChatGPTに流行りの「今まで私があなたをどう扱ってきたかを画像にして」を頼んでみた
ChatGPTのプロンプトを“自分用”に進化させる方法|頼み方で結果が激変する理由
初心者が最初にやりがちなプロンプトの失敗例と直し方
ChatGPTが急に賢くなる「前提条件」の渡し方-同じ質問なのに答えが変わるのはなぜ?-
プロンプトを毎回書かなくてよくなる“会話の残し方”
ChatGPTに「察してもらえない」と感じた時の原因と対処法|噛み合わない理由を実例で解説
AIに雑に投げても失敗しにくくなる頼み方のコツ|考えずに使っても噛み合う方法
プロンプトが思いつかない人のための“最初の一文”テンプレ集
ChatGPTを“相棒化”する人と、うまく使えない人の決定的な差
生成AIはどこまで使っていい?初心者が最初に知るべき法律の話
AI画像生成は違法?著作権で“やってはいけないこと”実例集
商用利用OK?NG?生成AIの利用規約を初心者向けに噛み砕く
AIで作った文章は誰のもの?著作権の考え方をやさしく解説
「知らなかった」では済まない?生成AIトラブル事例と回避法
ブログ・SNSでAI生成物を使うときの最低限の注意点まとめ
AIに頼りすぎて思考力が落ちた話|便利さの裏で起きたリアル失敗
AIの回答を信じて怒られた話|正しいはずが通用しなかった理由
ChatGPTにExcelマクロを直してもらったらコメントが消えた話|親切の落とし穴
Copilotの差分コードが分からなかった話|全コード出してもらう選択
ChatGPTにきれいな文章はいらなかった話|ぐちゃぐちゃでも伝わる
ChatGPTは仕事に使うだけじゃない|高校生の恋愛LINEをChatGPTに相談したら既読スルーが減った話
ChatGPTは仕事に使うだけじゃない|バツイチ48歳のマッチングアプリ不安を解消した相談実例
ChatGPTは仕事に使うだけじゃない|社内不倫の相談を法と気持ちで整理した話
ChatGPTは仕事に使うだけじゃない|離婚前に確認すべきことを全部整理してくれた話
ChatGPTは仕事に使うだけじゃない|夫が不倫しているかも…調べ方を相談してみた話
ChatGPTは仕事に使うだけじゃない|高校生の反抗期の息子への声かけを相談してみた話
ChatGPTは仕事に使うだけじゃない|大阪のマンションごみトラブルを理事会で相談した話
ChatGPTは仕事に使うだけじゃない|社内報の“ビックリマン風・ジブリ風”画像を作った話
ChatGPTは仕事に使うだけじゃない|ママ友ランチ角が立たず断れた話
ChatGPTは仕事に使うだけじゃない|会話ゼロ夫婦が再出発できた話
ChatGPTは仕事に使うだけじゃない|派遣切り50代女性の次の仕事を相談した話
ChatGPTは仕事に使うだけじゃない|これから役立つ資格をAIに本気で相談してみた話
ChatGPTは仕事に使うだけじゃない|親の介護が不安で今から準備を聞いた話
ChatGPTは仕事に使うだけじゃない|PTA役員を角が立たず断れた話
ChatGPTは仕事に使うだけじゃない|義母との距離感がしんどい悩みを整理してもらった話
ChatGPTは仕事に使うだけじゃない|家計が苦しい時に大阪市で使える制度を年齢別に聞いた話
ChatGPTは仕事に使うだけじゃない|子どものスマホルールを一緒に作ってみた話
ChatGPTは仕事に使うだけじゃない|推し活にお金を使いすぎる悩みを整理してもらった話
ChatGPTは仕事に使うだけじゃない|人間関係がしんどくて距離を置きたい時の相談実例
ChatGPTは仕事に使うだけじゃない|将来が不安で眠れない50歳手前女性の相談を整理してもらった話
Copilotでクロス表を縦持ちデータに変換|実務VBA作成の流れ
Copilotでクロス表を縦持ちデータに変換|実務仕上げ編
Copilotでクロス表を縦持ちデータに変換|配列で高速化する
Copilotでクロス表を縦持ちデータに変換|項目変更に強い構造へ
Copilotでリストボックスにユニーク値を設定|実務VBA
Copilotでリストボックス並び替え対応|実務VBA
Copilotでリストボックス表示制御を追加|実務VBA
Copilotで階層連動コンボボックス作成|実務VBA
Copilotで列番号を動的管理|階層連動VBAの実務改善