【2025年9月】
前回「CSVファイルを読み込むマクロを作って」を検証したら、なんか大変なことになりました。ちなみに、詳しくは下記のページをご覧ください。
いきなり外部ファイルの操作をお願いしたのは、無理があったかもしれません。やっぱ、Excelのマクロといえば、セルやシートの操作ですよね。なので今回は、シート操作に関する検証です。

アクティブブックのアクティブシートに、上図のようなデータがあります。シートの名前は「Sheet1」です。このシートを、独立した新しいブックとして保存します。新しく保存するブックの名前は「C:\Data\202509.xlsx」とします。
アクティブシートのデータを、新しいブックで保存するVBAのコードを作って。保存するブックの名前は「C:\Data\202509.xlsx」です。
Sub SaveActiveSheetToNewWorkbook()
Dim newWb As Workbook
ActiveSheet.Copy
Set newWb = ActiveWorkbook
newWb.SaveAs Filename:="C:\Data\202509.xlsx", FileFormat:=xlOpenXMLWorkbook
newWb.Close SaveChanges:=False
End Sub
おお、良いコードですね。特定のシートを新しいブックとして保存するとき「新規ブックを挿入→該当シートを新規ブックにコピー」という手順は無駄です。「ActiveSheet.Copy」だけで、アクティブシートだけが、新しいブックになります。この操作は、[ホーム]タブ-[書式]-[シートの移動またはコピー]をクリックして表示される[移動またはコピー]ダイアログボックスの「移動先ブック名」リストで「(新しいブック)」を選択したときの動作です。

私だったら、オブジェクト変数を使わないで、次のように書きますね。
Sub SaveActiveSheetToNewWorkbook()
ActiveSheet.Copy
ActiveWorkbook.SaveAs Filename:="C:\Data\202509.xlsx", FileFormat:=xlOpenXMLWorkbook
ActiveWorkbook.Close SaveChanges:=False
End Sub
AIはオブジェクト変数が好きですからね。これも個性でしょうか。さて、上記のマクロでは、もし「C:\Data」フォルダに、すでに"202509.xlsx"が存在すると止まってしまいます。

(ここに上記のコードを貼り付けました) このマクロでは、すでに"C:\Data\202509.xlsx"が存在するとマクロが止まります。同じ名前のブックが存在したら「上書き保存」するには?
Sub SaveActiveSheetToNewWorkbook()
Dim newWb As Workbook
Dim filePath As String
filePath = "C:\Data\202509.xlsx"
' 既存ファイルがあれば削除
If Dir(filePath) <> "" Then
Kill filePath
End If
ActiveSheet.Copy
Set newWb = ActiveWorkbook
newWb.SaveAs Filename:=filePath, FileFormat:=xlOpenXMLWorkbook
newWb.Close SaveChanges:=False
End Sub
なるほど「上書き保存」するのではなく、既存ファイルを削除してから保存する作戦ですね。Dir関数は、引数に指定したファイルが存在するとファイル名を返し、存在しないと空欄を返します。「<> ""」は「空欄ではない=存在する」という意味です。続くKillステートメントは、引数に指定したファイルを削除します。ちなみに、ゴミ箱へ移動ではなく、完全削除です。
既存ファイルがあったら「キャンセルする」方も作ってもらいましょう。
(ここに最初のコードを貼り付けました)
このマクロでは、すでに"C:\Data\202509.xlsx"が存在するとマクロが止まります。同じ名前のブックが存在したら「キャンセル」するには?
Sub SaveActiveSheetToNewWorkbook()
Dim filePath As String
filePath = "C:\Data\202509.xlsx"
' ファイルが存在したらキャンセル
If Dir(filePath) <> "" Then
MsgBox "同じ名前のファイルが存在するため、保存をキャンセルしました。", vbExclamation
Exit Sub
End If
ActiveSheet.Copy
ActiveWorkbook.SaveAs Filename:=filePath, FileFormat:=xlOpenXMLWorkbook
ActiveWorkbook.Close SaveChanges:=False
End Sub
まぁ、そうなりますね。Exit Subは、実行中のプロシージャを強制終了します。
さて、今回保存するファイル名「202509.xlsx」の"202509"部分は、現在の年月です。これを、たとえば来月になったら"202510.xlsx"と自動的にするには?
(ここに最初のコードを貼り付けました)
保存するファイル名のうち「202509」を、現在の年月にするには?
Sub SaveActiveSheetToNewWorkbook()
Dim newWb As Workbook
Dim filePath As String
filePath = "C:\Data\" & Format(Date, "yyyymm") & ".xlsx"
ActiveSheet.Copy
Set newWb = ActiveWorkbook
newWb.SaveAs Filename:=filePath, FileFormat:=xlOpenXMLWorkbook
newWb.Close SaveChanges:=False
End Sub
Dateは、現在の日付を返すステートメント(関数じゃありません)で、Formatは表示形式の結果を返す関数です。
ここまでは、アクティブシートをそのままブックとして保存しましたけど、アクティブシートのリストに対して、「名前」列を"田中"でフィルタし、その結果を保存するようにしたいです。実務で超あるあるですね。
アクティブシートのリストを「2列目が"田中"と等しい」でフィルタし、フィルタした結果を新しいブックとして保存するVBAのコードを作って。保存するブックの名前は「C:\Data\202509.xlsx」です。
Sub FilterAndSaveTanaka()
Dim ws As Worksheet
Dim wbNew As Workbook
Dim rng As Range
Set ws = ActiveSheet
Set rng = ws.UsedRange
' 2列目が「田中」の行でフィルタ
rng.AutoFilter Field:=2, Criteria1:="田中"
' 新しいブックを作成し、フィルタ結果をコピー
Set wbNew = Workbooks.Add
rng.SpecialCells(xlCellTypeVisible).Copy Destination:=wbNew.Sheets(1).Range("A1")
' フィルタ解除
ws.AutoFilterMode = False
' 新しいブックを保存
wbNew.SaveAs Filename:="C:\Data\202509.xlsx", FileFormat:=xlOpenXMLWorkbook
wbNew.Close SaveChanges:=False
End Sub
SpecialCells(xlCellTypeVisible) は、いわゆる"可視セル選択"です。本当はこれ、不要なんですけどね。まぁ、無駄が多いのも、ある意味でAIの個性でしょう。ちなみに、私が書くなら、次のようにします。
Sub FilterAndSaveTanaka2()
Dim rng As Range
Set rng = ActiveSheet.UsedRange
rng.AutoFilter 2, "田中"
Workbooks.Add
rng.Copy Range("A1")
rng.Parent.AutoFilterMode = False
ActiveWorkbook.SaveAs "C:\Data\202509.xlsx"
ActiveWorkbook.Close
End Sub
最後に、複数のリストを縦に結合して、その結果を保存するマクロを作ってもらいます。ここまでの流れでいくと、かなり期待できそうですね。
[9月]シートと[10月]シートに、それぞれリストがあります。どちらのリストもヘッダは「日付・名前・記号・地域・数値」ですが、データの件数(行数)は未定です。新しいワークシートを挿入し、そこに[9月]シートのリストと[10月]シートのリストを結合して、結合した結果を新しいブックとして保存するVBAのコードを作って。保存するブックの名前は「C:\Data\202509.xlsx」です。
さて、伝わるかな?
Sub MergeAndSaveLists()
Dim ws9 As Worksheet, ws10 As Worksheet, wsNew As Worksheet
Dim lastRow9 As Long, lastRow10 As Long, lastCol As Long
Dim wbNew As Workbook
Set ws9 = ThisWorkbook.Sheets("9月")
Set ws10 = ThisWorkbook.Sheets("10月")
' 新しいワークシートを追加
Set wsNew = ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
wsNew.Name = "結合リスト"
' 9月シートのデータをコピー
lastRow9 = ws9.Cells(ws9.Rows.Count, 1).End(xlUp).Row
lastCol = ws9.Cells(1, ws9.Columns.Count).End(xlToLeft).Column
ws9.Range(ws9.Cells(1, 1), ws9.Cells(lastRow9, lastCol)).Copy wsNew.Cells(1, 1)
' 10月シートのデータをコピー(ヘッダを除く)
lastRow10 = ws10.Cells(ws10.Rows.Count, 1).End(xlUp).Row
ws10.Range(ws10.Cells(2, 1), ws10.Cells(lastRow10, lastCol)).Copy wsNew.Cells(lastRow9 + 1, 1)
' 新しいブックを作成して貼り付け
Set wbNew = Workbooks.Add
wsNew.UsedRange.Copy wbNew.Sheets(1).Cells(1, 1)
wbNew.SaveAs Filename:="C:\Data\202509.xlsx", FileFormat:=xlOpenXMLWorkbook
wbNew.Close SaveChanges:=False
MsgBox "結合して保存しました。"
End Sub
上から順番に解説します。まず「ThisWorkbook」とは、このマクロが書かれているブックを表します。もし、同時に複数のブックが開いていると、どのブックがアクティブブックになるか分かりませんので、誤動作を避けるために、よく使います。なので、安全のためには必要なのですが、いかんせん、スペルが長いです。その結果、次の「新しいシートを挿入する」部分が、とても冗長に見えます。この長さになると、ビギナーは読むのにも苦労するでしょう。なので、私だったら、この「ThisWorkbook」をWithで括ります。AIが提示するコードでは、あまりWithを見かけませんが、可読性を高めるためにも、積極的に利用したいです。Withを使うと、次のように短くなります。
【Before】
Set ws9 = ThisWorkbook.Sheets("9月")
Set ws10 = ThisWorkbook.Sheets("10月")
' 新しいワークシートを追加
Set wsNew = ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
wsNew.Name = "結合リスト"
【After】
With ThisWorkbook
Set ws9 = .Sheets("9月")
Set ws10 = .Sheets("10月")
' 新しいワークシートを追加
Set wsNew = .Sheets.Add(After:=.Sheets(.Sheets.Count))
wsNew.Name = "結合リスト"
End With
このマクロのポイントは、9月のデータはヘッダごとコピーするけど、10月のデータはヘッダを除いた実データ部分(2行目から下)をコピーするところです。提示されたコードでは、Range(左上, 右下)の"左上"を、9月→セルA1、10月→セルA2と指定することで対処しています。見事です。
最後の「新しいブックを作成して貼り付け」は、ちょっと残念ですね。最初に提示されたコードでは、同じ処理を「ActiveSheet.Copy」とシンプルに実行しています。その方法を知っているのなら、今回も使って欲しかったです。このへんが、AI特有の"ゆらぎ"や"ぶれ"なのでしょうね。同じ結果でも、異なる書き方はたくさんあります。プログラムを作る人は、その人なりの主義や主張を持ち、一貫性のある統一されたコードを書きます。その方が、メンテナンスやデバッグしやすいからです。AIに部分的なコードを書いてもらうと、そのときによって一貫性のないコードが提示されます。それを、そのままコピーして寄せ集めると、結局「何をやっているのか分からない」「担当者がいないと直せない」などの属人化を招くでしょうね。気をつけたいものです。
さて、最後の「9月と10月を結合して保存する」ですが、かなり反則ですけど、私だったら次のようにしますね。
Sub Sample1()
Sheets.Add.Name = "結合リスト"
Range("A1").Formula2 = "=VSTACK('9月'!A:.E,DROP('9月'!A:.E,1))"
Range("A:A").NumberFormat = "yyyy/m/d"
Range("A1#").Value = Range("A1#").Value
ActiveSheet.Copy
ActiveWorkbook.SaveAs "C:\Data\202509.xlsx"
ActiveWorkbook.Close
End Sub
2つのリストを結合するなんて、今のExcelだったら、ワークシート関数の方が簡単です。結合する数式を一度セルに入れて、その結果を値貼り付けしています。まぁ、AIは絶対に提示しないでしょうけどw もちろん、VSTACK関数、DROP関数、TRIMRANGE関数が使えるExcelでしか動作しません。