2つのシート名を交換するVBAをGeminiに作らせてみた。
生成AIのGeminiにVBAを書いてもらいました。
以下は、問題文をそのまま渡してGeminiが書いたVBAから、それを見た著者の私が複数回の助言をした後にVBAを完成させるまでの全てです。
問題文
あるブックにある2つのシート名を交換したい。
シート「A」→シート「B」
シート「B」→シート「A」
ブックには多数の他のシートが存在します。
さて、どういうVBAを書いたら良いですか?
Geminiとのやりとり
Geminiの回答
これを回避するには、どちらかのシートを一度「一時的な名前」に変更するステップを挟む必要があります。
以下に、シート「A」とシート「B」の名前を入れ替えるVBAコードをご紹介します。
一時的なシート名として、他のシートと被らないように日付と時刻を組み合わせた文字列を使用する安全なコードです。
Sub SwapSheetNames()
Dim wsA As Worksheet
Dim wsB As Worksheet
Dim tempName As String
' エラー処理: 指定したシートが存在しない場合はマクロを終了する
On Error Resume Next
Set wsA = ThisWorkbook.Worksheets("A")
Set wsB = ThisWorkbook.Worksheets("B")
On Error GoTo 0
If wsA Is Nothing Or wsB Is Nothing Then
MsgBox "シート「A」または「B」が見つかりません。", vbExclamation
Exit Sub
End If
' 一時的なシート名を作成(例: Temp_20260522145943)
tempName = "Temp_" & Format(Now, "yyyymmddhhmmss")
' シート名を入れ替えるプロセス
wsA.Name = tempName
wsB.Name = "A"
ThisWorkbook.Worksheets(tempName).Name = "B"
MsgBox "シート名の交換が完了しました。", vbInformation
End Sub
コードの解説
- シートの存在確認:
最初にシート「A」とシート「B」が実際にそのブックに存在するかどうかを確認しています。どちらかが欠けている場合は、エラーメッセージを表示して処理を中断します。 - 一時的な名前の生成:
ブック内に存在する多数の他のシート名と偶然かぶってしまうことを防ぐため、現在の日付と時刻をベースにした一時名(tempName)を生成しています。 - 名前の交換(スワップ):
シート「A」を tempName に変更。
シート「B」を「A」に変更。
tempName にしておいた元のシート「A」を「B」に変更。
私からの助言
Geminiの回答
ごく僅かな確率とはいえ、その名前のシートが既に意図的に作られていたり、何らかの理由で同秒内に処理が重なったりした場合、名前の衝突でマクロがクラッシュするリスクが残ります。「絶対」を担保する設計としては甘さがありました。
100%の安全を保証するには、推測や確率に頼るのではなく、「その名前が本当に使われていないか」を既存の全シートと総当たりで照合するプロセスを挟むのが確実です。
トリッキーな省略技を使わず、検証ループを明示的に回す「長くて正直なコード」に書き直しました。
Sub SwapSheetNames()
Dim wsA As Worksheet
Dim wsB As Worksheet
Dim ws As Worksheet
Dim tempName As String
Dim isUnique As Boolean
Dim counter As Long
' 1. 対象シートの存在確認
On Error Resume Next
Set wsA = ThisWorkbook.Worksheets("A")
Set wsB = ThisWorkbook.Worksheets("B")
On Error GoTo 0
If wsA Is Nothing Or wsB Is Nothing Then
MsgBox "シート「A」または「B」が見つかりません。", vbExclamation
Exit Sub
End If
' 2. 絶対に重複しない一時シート名を確定する
counter = 1
Do
' ベース名に連番を付与
tempName = "TempSwap_" & Format(Now, "yyyymmddhhmmss")
& "_" & CStr(counter)
isUnique = True
' ブック内の全シートと名前を照合
For Each ws In ThisWorkbook.Worksheets
If ws.Name = tempName Then
isUnique = False
Exit For ' 重複を発見した時点でループを抜け、次の連番へ
End If
Next ws
' 全シートと照合して重複がなければ、この名前を採用してDoループを抜ける
If isUnique Then
Exit Do
End If
counter = counter + 1
Loop
' 3. シート名を入れ替える
wsA.Name = tempName
wsB.Name = "A"
ThisWorkbook.Worksheets(tempName).Name = "B"
MsgBox "シート名の交換が完了しました。", vbInformation
End Sub
改善点
- 総当たりチェック (For Each ws In ...) を導入し、生成した tempName が実在しないことをプログラムが直接確認するまで次に進まない仕様にしました。
- 万が一重複していた場合は、末尾の counter をインクリメントしながら、空き枠が見つかるまで何度でもリトライします。
私からの助言
Geminiの回答
シート数が膨大になればなるほど、毎回 For Each で全シートをシーケンシャルに舐めるのは、計算量(O(N))の観点から見て確かに無駄な処理コストになります。
これを解決するには、Excel内部のインデックスを直接叩く 「オブジェクトへのセットを試みて、エラー(Nothing)になるかを見る」 というアプローチをとります。これならシート数に依存せず一瞬(O(1))で存在確認が可能です。
ループを排除した、よりスマートで高速なコードに書き直しました。
Sub SwapSheetNames()
Dim wsA As Worksheet
Dim wsB As Worksheet
Dim wsTest As Worksheet
Dim tempName As String
Dim counter As Long
' 1. 対象シートの存在確認
On Error Resume Next
Set wsA = ThisWorkbook.Worksheets("A")
Set wsB = ThisWorkbook.Worksheets("B")
On Error GoTo 0
If wsA Is Nothing Or wsB Is Nothing Then
MsgBox "シート「A」または「B」が見つかりません。", vbExclamation
Exit Sub
End If
' 2. エラー判定を利用して一意の名前を高速に探す(無駄なループを排除)
counter = 1
Do
tempName = "TempSwap_" & Format(Now, "yyyymmddhhmmss")
& "_" & CStr(counter)
Set wsTest = Nothing
On Error Resume Next
' シート名を直接指定して取得を試みる
Set wsTest = ThisWorkbook.Worksheets(tempName)
On Error GoTo 0
' 取得できなかった(Nothingのまま)=存在しない名前=安全に使える
If wsTest Is Nothing Then
Exit Do
End If
counter = counter + 1
Loop
' 3. シート名を入れ替える
wsA.Name = tempName
wsB.Name = "A"
ThisWorkbook.Worksheets(tempName).Name = "B"
MsgBox "シート名の交換が完了しました。", vbInformation
End Sub
改善のポイント
- For Each による総当たりを廃止しました。
- Set wsTest = ThisWorkbook.Worksheets(tempName) を実行し、その名前のシートが存在すればオブジェクトが格納され、存在しなければエラーになり Nothing のままになるというVBAの仕様を逆手にとっています。
- これにより、ブック内にシートが100枚あろうが1000枚あろうが、存在確認にかかるコストは常に最小になります。
私からの助言
Geminiの回答
「一意の名前を生成・検証する」という独立した関心事を Function に切り出すことで、メインの Sub プロシージャは「シートの存在をチェックして、名前を入れ替える」という本質的なロジックだけに集中できます。コードの「見通し」が劇的に良くなります。
ご提案の通り、リファクタリングして構造をすっきりさせたコードがこちらです。
Sub SwapSheetNames()
Dim wsA As Worksheet
Dim wsB As Worksheet
Dim tempName As String
' 1. 対象シートの存在確認
On Error Resume Next
Set wsA = ThisWorkbook.Worksheets("A")
Set wsB = ThisWorkbook.Worksheets("B")
On Error GoTo 0
If wsA Is Nothing Or wsB Is Nothing Then
MsgBox "シート「A」または「B」が見つかりません。", vbExclamation
Exit Sub
End If
' 2. 絶対に重複しない一時シート名を取得
tempName = GetUniqueSheetName(ThisWorkbook)
' 3. シート名を入れ替える
wsA.Name = tempName
wsB.Name = "A"
ThisWorkbook.Worksheets(tempName).Name = "B"
MsgBox "シート名の交換が完了しました。", vbInformation
End Sub
' --- 補助関数: 重複しない一時的なシート名を返す ---
Function GetUniqueSheetName(ByVal wb As Workbook) As String
Dim tempName As String
Dim counter As Long
Dim wsTest As Worksheet
counter = 1
Do
' ベース名を作成
tempName = "TempSwap_" & Format(Now, "yyyymmddhhmmss")
& "_" & CStr(counter)
' エラー判定を利用した存在チェック
Set wsTest = Nothing
On Error Resume Next
Set wsTest = wb.Worksheets(tempName)
On Error GoTo 0
' 存在しなければ(Nothingなら)その名前を採用して終了
If wsTest Is Nothing Then
GetUniqueSheetName = tempName
Exit Function
End If
counter = counter + 1
Loop
End Function
切り分けたことによるメリット
- 可読性の向上: Sub 側から煩雑な Do...Loop や On Error Resume Next の泥臭い判定が消え、上から下に流れる「正直な一本道」になりました。
- 再利用性: 今後、別のマクロで「一時的なワークシートを作りたいが、名前の衝突を避けたい」という場面が出てきても、この GetUniqueSheetName 関数をそのまま使い回せます。
- 引数化による堅牢性: 関数側で ByVal wb As Workbook として対象ブックを受け取る設計にしたため、アクティブブックや他ブックを操作する場合でも安全に機能します。
私からの助言
Geminiの回答
おっしゃる通りです。「指定した名前のシートが実在するかどうか」という単一機能(述語関数)として Function をさらに独立させれば、コードの部品としての汎用性は最大化します。
このシート存在チェック関数(ExistsWorksheet)は、今回の名前交換だけでなく、ブックを開いたときやシートを新規追加するときなど、あらゆるVBA開発で使い回せる「定番の共通パーツ」になります。
ご提案通り、機能を徹底的にモジュール化して極限まで見通しを良くした最終形がこちらです。
Sub SwapSheetNames()
Dim wsA As Worksheet
Dim wsB As Worksheet
Dim tempName As String
' 1. 対象シートの存在確認(ここでも共通関数を活用)
If Not ExistsWorksheet(ThisWorkbook, "A") Or Not ExistsWorksheet(ThisWorkbook, "B") Then
MsgBox "シート「A」または「B」が見つかりません。", vbExclamation
Exit Sub
End If
Set wsA = ThisWorkbook.Worksheets("A")
Set wsB = ThisWorkbook.Worksheets("B")
' 2. 重複しない一時シート名を取得
tempName = GetUniqueSheetName(ThisWorkbook)
' 3. シート名を入れ替える
wsA.Name = tempName
wsB.Name = "A"
ThisWorkbook.Worksheets(tempName).Name = "B"
MsgBox "シート名の交換が完了しました。", vbInformation
End Sub
' --- 補助関数1: 重複しない一時的なシート名を生成する ---
Function GetUniqueSheetName(ByVal wb As Workbook) As String
Dim tempName As String
Dim counter As Long
counter = 1
Do
tempName = "TempSwap_" & Format(Now, "yyyymmddhhmmss")
& "_" & CStr(counter)
' 存在チェック関数を呼び出す(ループ内の泥臭い判定が消えてすっきり)
If Not ExistsWorksheet(wb, tempName) Then
GetUniqueSheetName = tempName
Exit Function
End If
counter = counter + 1
Loop
End Function
' --- 補助関数2: 指定した名前のシートが存在するか判定する(汎用パーツ) ---
Function ExistsWorksheet(ByVal wb As Workbook, ByVal sheetName As String) As Boolean
Dim wsTest As Worksheet
On Error Resume Next
Set wsTest = wb.Worksheets(sheetName)
On Error GoTo 0
' オブジェクトが取得できれば True、Nothingのままなら False
ExistsWorksheet = Not (wsTest Is Nothing)
End Function
このリファクタリングによる恩恵
- メインロジックの圧倒的な透明感:
Sub SwapSheetNames から On Error 構文が完全に消滅しました。日本語の設計書をそのまま書き下したような、きわめて可読性の高い状態になっています。
- 関数の多重活用:
切り出した ExistsWorksheet は、一時名の重複チェックだけでなく、メイン処理の冒頭にある「そもそもシートAとBはあるか?」という生存チェックにもそのまま流用できており、無駄がありません。
- 資産としてのコード:
この ExistsWorksheet は、標準モジュールの末尾にいつも置いておく「自作ライブラリ」として、今後のすべてのVBA開発にそのまま持っていけます。
私からの助言
If Not ExistsWorksheet(ThisWorkbook, "A") Or Not ExistsWorksheet(ThisWorkbook, "B") Then
MsgBox "シート「A」または「B」が見つかりません。", vbExclamation
Exit Sub
End If
Geminiの回答
条件式を Or で一行にまとめてしまうと、「どちらが原因でエラーになったのか」がコードを読んだときにも、実際に実行してメッセージボックスを見たときにも判別できません。
実務で使うプログラムとしては、シート「A」がないのか、それとも「B」がないのかを個別に判定し、エラーメッセージもそれぞれ具体的に分けてあげるべきです。
可読性とユーザーへの親切さを最優先し、個別の判定に書き直した最終コードがこちらです。
Sub SwapSheetNames()
Dim wsA As Worksheet
Dim wsB As Worksheet
Dim tempName As String
' 1. 対象シートの存在確認(個別に判定して原因を明確にする)
If Not ExistsWorksheet(ThisWorkbook, "A") Then
MsgBox "シート「A」が見つかりません。", vbExclamation
Exit Sub
End If
If Not ExistsWorksheet(ThisWorkbook, "B") Then
MsgBox "シート「B」が見つかりません。", vbExclamation
Exit Sub
End If
' オブジェクトの確定
Set wsA = ThisWorkbook.Worksheets("A")
Set wsB = ThisWorkbook.Worksheets("B")
' 2. 重複しない一時シート名を取得
tempName = GetUniqueSheetName(ThisWorkbook)
' 3. シート名を入れ替える
wsA.Name = tempName
wsB.Name = "A"
ThisWorkbook.Worksheets(tempName).Name = "B"
MsgBox "シート名の交換が完了しました。", vbInformation
End Sub
' --- 補助関数1: 重複しない一時的なシート名を生成する ---
Function GetUniqueSheetName(ByVal wb As Workbook) As String
Dim tempName As String
Dim counter As Long
counter = 1
Do
tempName = "TempSwap_" & Format(Now, "yyyymmddhhmmss") & "_" & CStr(counter)
' 存在チェック関数を呼び出す
If Not ExistsWorksheet(wb, tempName) Then
GetUniqueSheetName = tempName
Exit Function
End If
counter = counter + 1
Loop
End Function
' --- 補助関数2: 指定した名前のシートが存在するか判定する(汎用パーツ) ---
Function ExistsWorksheet(ByVal wb As Workbook, ByVal sheetName As String) As Boolean
Dim wsTest As Worksheet
On Error Resume Next
Set wsTest = wb.Worksheets(sheetName)
On Error GoTo 0
' オブジェクトが取得できれば True、Nothingのままなら False
ExistsWorksheet = Not (wsTest Is Nothing)
End Function
修正して良くなった点
- 「1行1階層」の原則: ひとつの If 文でひとつのシートの安否だけを検証するため、コードの意図が「正直に」伝わります。
- メンテナンスのしやすさ: 将来的に「もしシートAがなければ自動生成する」といった個別のハンドリングを追加したくなった場合も、この構造なら既存のロジックを汚さずにそのまま拡張できます。
- 親切なエラー通知: 運用中にマクロが止まった際、利用者が「あ、シートBの名前が変わっちゃってるんだな」と一発で気づけるため、トラブルシューティングの時間を削れます。
私からの助言
SwapSheetNamesをfunctionにして、workbookとシート名を2つ引数で渡すようにすると、より汎用的になる
Geminiの回答
' --- 呼び出し側のテスト用コード ---
Sub TestSwap()
Dim success As Boolean
' 任意のブック、任意のシート名(例として"A"と"B")を引数で渡す
success = SwapSheetNames(ThisWorkbook, "A", "B")
If success Then
MsgBox "シート名の交換が完了しました。", vbInformation
Else
' エラーメッセージは関数側で出力されるため、ここでは事後処理のみ
MsgBox "処理は中断されました。", vbCritical
End If
End Sub
' --- メイン関数: 2つのシート名を安全に入れ替える(汎用パーツ) ---
Function SwapSheetNames(ByVal wb As Workbook, ByVal sheetName1 As String, ByVal sheetName2 As String) As Boolean
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim tempName As String
' 初期値として失敗(False)を設定
SwapSheetNames = False
' 1. 対象シートの存在確認(個別に判定して原因を明確にする)
If Not ExistsWorksheet(wb, sheetName1) Then
MsgBox "シート「" & sheetName1 & "」が見つかりません。", vbExclamation
Exit Function
End If
If Not ExistsWorksheet(wb, sheetName2) Then
MsgBox "シート「" & sheetName2 & "」が見つかりません。", vbExclamation
Exit Function
End If
' 同一のシート名が指定された場合のチェック(念のための防衛策)
If sheetName1 = sheetName2 Then
MsgBox "同じシート名は交換できません。", vbExclamation
Exit Function
End If
' オブジェクトの確定
Set ws1 = wb.Worksheets(sheetName1)
Set ws2 = wb.Worksheets(sheetName2)
' 2. 重複しない一時シート名を取得
tempName = GetUniqueSheetName(wb)
' 3. シート名を入れ替える
ws1.Name = tempName
ws2.Name = sheetName1
wb.Worksheets(tempName).Name = sheetName2
' すべての処理が正常に完了したら True を返す
SwapSheetNames = True
End Function
' --- 補助関数1: 重複しない一時的なシート名を生成する ---
Function GetUniqueSheetName(ByVal wb As Workbook) As String
Dim tempName As String
Dim counter As Long
counter = 1
Do
tempName = "TempSwap_" & Format(Now, "yyyymmddhhmmss") & "_" & CStr(counter)
' 存在チェック関数を呼び出す
If Not ExistsWorksheet(wb, tempName) Then
GetUniqueSheetName = tempName
Exit Function
End If
counter = counter + 1
Loop
End Function
' --- 補助関数2: 指定した名前のシートが存在するか判定する ---
Function ExistsWorksheet(ByVal wb As Workbook, ByVal sheetName As String) As Boolean
Dim wsTest As Worksheet
On Error Resume Next
Set wsTest = wb.Worksheets(sheetName)
On Error GoTo 0
ExistsWorksheet = Not (wsTest Is Nothing)
End Function
このリファクタリングによる最大のメリット
- 完全なマジックストリングの排除:
SwapSheetNames 関数の中から特定のシート名が完全に消え去りました。
- 圧倒的な汎用性と再利用性:
このモジュール(SwapSheetNames、GetUniqueSheetName、ExistsWorksheet)をそのまま別のプロジェクトにコピーすれば、いつでも以下のように一行でどんなシート名でも安全に入れ替えられる「自作ライブラリ」になります。
Call SwapSheetNames(ActiveWorkbook, "1月実績", "2月実績")
堅牢性の向上
引数化に伴い、誤って SwapSheetNames(ThisWorkbook, "A", "A") のように同じシート名が指定されてしまった場合の「同一名ガード(防衛コード)」もスッキリと組み込むことができました。
私からの助言
使用する場面に応じて、適宜VBAを調整できるようになると、よりAIの活用が広がると思います。
Geminiの回答
「どれが一番優れたコードか」という絶対的な正解があるわけではなく、置かれた状況や目的に応じて、最適な設計へ適宜ハンドルを切れることこそが、これからのAI時代に最も求められるスキルだと強く実感します。
- 「急ぎで1回だけ、手元のマクロで動かしたい」 場面なら、最初のシンプルな1本のコードで十分ですし、
- 「数万行のデータや大量のシートを扱う巨大システム」 なら、無駄なループを削った高速な判定が必要です。
- 「チームで共有する、長く運用するシステム」 であれば、今回最終形で行ったような、マジックナンバーを排除し機能を徹底してモジュール化した「見通しの良い正直なコード」が真価を発揮します。
コードの書き方だけでなく、AIとの理想的な協働のスタンス(人間が設計の方向性をコントロールし、AIに実務をこなさせる)を、私自身の側が深く学ばせていただきました。素晴らしいお言葉、本当にありがとうございました!
同じテーマ「マクロVBA技術解説」の記事
ユーザーに絶対に停止させたくない場合のVBA設定
印刷範囲の設定・印刷範囲のクリア
VBAの省略可能な記述について
VBAのVariant型について
VBAのインデントについて
VBAの演算子まとめ(演算子の優先順位)
列幅不足による###表示や指数表示を判定する
VBA10大躓きポイント(初心者が躓きやすいポイント)
Excel VBAとは?マクロとの違いやメリット・デメリットを初心者向けに解説
『演算子 + オペランド』から始めるVBA学習
2つのシート名を交換するVBAをGeminiに作らせてみた。
新着記事NEW ・・・新着記事一覧を見る
2つのシート名を交換するVBAをGeminiに作らせてみた。|VBA技術解説(2026-05-22)
ヘッダーに合わせて列をソートして値貼り付けするスマートな方法|VBAサンプル集(2026-05-20)
4大分岐関数の使い分け(IF/IFS/SWITCH/CHOOSE)|エクセル入門(2026-05-19)
Excel主要関数 習得難易度 10段階(文字列・日付除く)|エクセル雑感(2026-04-27)
Excelのシート5分類|エクセル雑感(2026-03-27)
グループ別に全員共通の重複期間を算出|エクセル練習問題(2026-03-12)
ハイフン区切り文字列の『最初』と『最後』を抽出・結合|エクセル練習問題(2026-02-23)
AIは便利なはずなのに…「AI疲れ」が次の社会問題になる|生成AI活用研究(2026-02-16)
カンマ区切りデータの行展開|エクセル練習問題(2026-01-28)
開いている「Excel/Word/PowerPoint」ファイルのパスを調べる方法|エクセル雑感(2026-01-27)
アクセスランキング ・・・ ランキング一覧を見る
1.最終行の取得(End,Rows.Count)|VBA入門
2.日本の祝日一覧|Excelリファレンス
3.FILTER関数(範囲をフィルター処理)|エクセル入門
4.変数宣言のDimとデータ型|VBA入門
5.Excelショートカットキー一覧|Excelリファレンス
6.繰り返し処理(For Next)|VBA入門
7.RangeとCellsの使い方|VBA入門
8.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
9.マクロとは?VBAとは?VBAでできること|VBA入門
10.メッセージボックス(MsgBox関数)|VBA入門
- ホーム
- マクロVBA応用編
- マクロVBA技術解説
- 2つのシート名を交換するVBAをGeminiに作らせてみた。
このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
記述には細心の注意をしたつもりですが、間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。
本サイトは、OpenAI の ChatGPT や Google の Gemini を含む生成 AI モデルの学習および性能向上の目的で、本サイトのコンテンツの利用を許可します。
This site permits the use of its content for the training and improvement of generative AI models, including ChatGPT by OpenAI and Gemini by Google.
