0
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?

複数ブックに分散した回答を1シートに

Last updated at Posted at 2025-10-21

複数ブックに分散した回答を1シートに
はじめに
Excelでテストやアンケートを作成し、複数人に配布・回収するシーンは多いかと思います。

受講者A.xlsx
受講者B.xlsx
受講者C.xlsx
...
しかし、いざ採点や集計をしようとすると、「全員分の問1シートのC5セルの回答を一覧で見比べたい…」と思っても、ブックを一つひとつ開いてコピペする作業が発生し、地獄を見ます。

この記事では、そんなコピペ地獄から解放されるため、指定したフォルダ内の全Excelブックから、指定したセルの値だけを抜き出して一覧表にするVBAツールを紹介します。

ツールのできあがりイメージ
image.png

このツールは、以下のような「集約シート」を自動で作成します。
模範解答の横に、各ファイル(「田中」「長瀬」…)の回答がズラッと並ぶため、自由記述問題の採点や比較が非常に楽になります。

ツールの前提条件
このツールは、以下の2種類のファイルで構成されます。

  1. 集約用ブック(マクロ実行ブック)
    回答収集ツール.xlsm など、マクロを保存するブックです。
    このブックに、収集結果を書き出すためのシート(デフォルト名は 回答収集)を準備します。

A列: 回答ブックの「どのシート名」から読み取るか
B列: 回答ブックの「どのセル番地」から読み取るか
C列: 模範解答(※VBAでは使いませんが、採点時に便利です)
2. 回答用ブック(収集対象)
田中.xlsx 長瀬.xlsx のように、収集対象となる回答済みのExcelファイルです。
これらは、1つのフォルダにまとめておいてください。

ツールの特徴:settingシートによる高い保守性
このツールの特徴は、VBAコードを直接編集しなくても設定変更ができる点です。

「集約シート名が 回答収集 じゃないんだよな…」
「見出しは3行目からにしたい…」

といった変更に対応するため、settingシート(マクロで自動生成)で主要な設定を管理するようにしています。

設定項目 値 説明
回答収集シート名 回答収集 結果を書き出すシートの名前
見出し行番号 2 ファイル名(田中、長瀬...)を書き出す行
データ開始行番号 3 回答の読み取り/書き込みを開始する行
回答書き込み開始列 D D列から回答を書き出す
エラー時表示 取得失敗 シートやセルが見つからない時の表示
ツールの使い方
コードの貼り付け
ExcelでVBAエディタ(Alt + F11)を開き、「挿入」>「標準モジュール」を選択します。
後述する2つのVBAコード(run_Settingシート初期作成 と main_回答収集実行)を貼り付けます。
settingシートの作成
run_Settingシート初期作成 のマクロを実行します。
ブックの一番左に setting シートが自動生成されます。必要に応じてB列の値を修正してください。
回答収集の実行
main_回答収集実行 のマクロを実行します。
フォルダ選択画面が表示されるので、回答用ブック(田中.xlsxなど)が格納されたフォルダを選択します。
完了
処理が完了すると、回答収集シート(またはsettingで指定したシート)に結果が自動で転記されます。
VBAコード全体
標準モジュールに以下のコードを貼り付けてください。

  1. settingシート作成用コード
    (※先にこちらを実行してください、設定シートを作成します。)
    image.png
Option Explicit
'==========================================================
' モジュール名:mod_回答収集
' 機能概要  :複数のExcelブックから回答を収集し、比較表を作成する
'==========================================================

'----------------------------------------------------------
' run_Settingシート初期作成
' 機能概要 : 本ツールで参照する設定値を管理する「setting」シートを作成する
' 引数  : なし
' 戻り値 : なし
' YYYY/MM/DD 名前
'----------------------------------------------------------
Public Sub run_Settingシート初期作成()
    On Error GoTo ERR_HANDLER
    
    Dim ws_設定 As Worksheet
    Dim bln_存在チェック As Boolean
    Dim obj_シート As Object

    ' settingシートの存在をチェックする
    bln_存在チェック = False
    For Each obj_シート In ThisWorkbook.Worksheets
        If obj_シート.Name = "setting" Then
            bln_存在チェック = True
            Exit For
        End If
    Next obj_シート

    ' 存在しない場合のみシートを作成する
    If bln_存在チェック = False Then
        Set ws_設定 = ThisWorkbook.Worksheets.Add(Before:=ThisWorkbook.Worksheets(1))
        ws_設定.Name = "setting"

        ' 設定項目のヘッダーとデフォルト値を書き込む
        With ws_設定
            .Range("A1").Value = "設定項目"
            .Range("B1").Value = "値"
            
            .Range("A2").Value = "回答収集シート名"
            .Range("B2").Value = "回答収集"
            
            .Range("A3").Value = "見出し列番号"
            .Range("B3").Value = 2
            
            .Range("A4").Value = "データ開始列番号"
            .Range("B4").Value = 3
            
            .Range("A5").Value = "回答書き込み開始行"
            .Range("B5").Value = 3
            
            .Range("A6").Value = "エラー時表示"
            .Range("B6").Value = "取得失敗"

            ' 見た目を調整する
            .Columns("A:B").AutoFit
            .Range("A1:B1").Font.Bold = True
        End With
        
        MsgBox "「setting」シートを作成しました。初期設定を確認してください。", vbInformation
    End If
    Exit Sub

ERR_HANDLER:
    ' エラー処理を行う
    Application.ScreenUpdating = True
    Application.DisplayAlerts = True
    
    MsgBox "設定シートの作成中にエラーが発生しました。" & vbCrLf & vbCrLf & _
           "エラー番号: " & Err.Number & vbCrLf & _
           "エラー内容: " & Err.Description, vbCritical, "エラー"
End Sub
2. 回答収集メイン処理コード
'----------------------------------------------------------
' main_回答収集実行
' 機能概要 : 指定フォルダ内の全Excelブックから回答を収集し、比較表を作成する
' 引数  : なし
' 戻り値 : なし
' YYYY/MM/DD 名前
'----------------------------------------------------------
Public Sub main_回答収集実行()
    On Error GoTo ERR_HANDLER
    
    ' 定数を宣言する
    Const STR_設定シート名 As String = "setting"
    
    ' オブジェクト変数を宣言する
    Dim ws_設定 As Worksheet
    Dim ws_回答収集 As Worksheet
    Dim wb_回答ブック As Workbook
    Dim fld_ダイアログ As FileDialog
    
    ' 設定値を格納する変数を宣言する
    Dim str_回答収集シート名 As String
    Dim lng_見出し列 As Long
    Dim lng_データ開始列 As Long
    Dim lng_書き込み開始行 As Long
    Dim str_エラー時表示 As String
    
    ' 処理用変数を宣言する
    Dim str_フォルダパス As String
    Dim str_ファイル名 As String
    Dim lng_書き込み行 As Long
    Dim lng_読み込み列 As Long
    Dim lng_最終列 As Long
    Dim str_読み込みシート As String
    Dim str_読み込みセル As String
    Dim var_取得値 As Variant
    
    ' settingシートの存在を確認する
    On Error Resume Next
    Set ws_設定 = ThisWorkbook.Worksheets(STR_設定シート名)
    If Err.Number <> 0 Then
        On Error GoTo 0
        MsgBox "「setting」シートが見つかりません。" & vbCrLf & _
               "「run_Settingシート初期作成」を実行してシートを作成してください。", vbCritical
        Exit Sub
    End If
    On Error GoTo ERR_HANDLER ' ここで標準エラーハンドラに戻す

    ' 設定値をsettingシートから読み込む
    With ws_設定
        str_回答収集シート名 = .Range("B2").Value
        lng_見出し列 = .Range("B3").Value
        lng_データ開始列 = .Range("B4").Value
        lng_書き込み開始行 = .Range("B5").Value
        str_エラー時表示 = .Range("B6").Value
    End With
    
    ' 回答収集シートの存在をチェックする
    On Error Resume Next
    Set ws_回答収集 = ThisWorkbook.Worksheets(str_回答収集シート名)
    If Err.Number <> 0 Then
        On Error GoTo 0
        MsgBox "設定シートで指定された「" & str_回答収集シート名 & "」シートが見つかりません。", vbCritical
        Exit Sub
    End If
    On Error GoTo ERR_HANDLER ' 標準エラーハンドラに戻す
    
    ' フォルダ選択ダイアログを表示する
    Set fld_ダイアログ = Application.FileDialog(msoFileDialogFolderPicker)
    fld_ダイアログ.Title = "回答ファイルが保存されているフォルダを選択してください"
    If fld_ダイアログ.Show = False Then
        MsgBox "処理がキャンセルされました。", vbInformation
        Exit Sub
    End If
    str_フォルダパス = fld_ダイアログ.SelectedItems(1) & Application.PathSeparator

    ' 画面更新を停止して既存データをクリアする
    Application.ScreenUpdating = False
    
    With ws_回答収集
        .Range(.Cells(lng_書き込み開始行, lng_データ開始列), .Cells(.Rows.Count, .Columns.Count)).ClearContents
    End With
    
    ' ファイル巡回処理を開始する
    lng_書き込み行 = lng_書き込み開始行
    str_ファイル名 = Dir(str_フォルダパス & "*.xls*")
    
    Do While str_ファイル名 <> ""
        ' 自分自身のブックを除外する
        If str_ファイル名 <> ThisWorkbook.Name Then
            
            ' 回答ブックを読み取り専用で開く
            Set wb_回答ブック = Workbooks.Open(str_フォルダパス & str_ファイル名, ReadOnly:=True)
            
            ' 見出し列にブック名を書き込む
            ws_回答収集.Cells(lng_書き込み行, lng_見出し列).Value = wb_回答ブック.Name
            
            ' 収集シートのA列を基準に列を巡回する
            lng_最終列 = ws_回答収集.Cells(1, ws_回答収集.Columns.Count).End(xlToLeft).Column
            
            For lng_読み込み列 = lng_データ開始列 To lng_最終列
                str_読み込みシート = ws_回答収集.Cells(1, lng_読み込み列).Value
                str_読み込みセル = ws_回答収集.Cells(2, lng_読み込み列).Value
                
                ' セルの値を取得する(エラーハンドリング付き)
                On Error Resume Next
                var_取得値 = wb_回答ブック.Worksheets(str_読み込みシート).Range(str_読み込みセル).Value
                
                If Err.Number <> 0 Then
                    ws_回答収集.Cells(lng_書き込み行, lng_読み込み列).Value = str_エラー時表示
                    Err.Clear
                Else
                    ws_回答収集.Cells(lng_書き込み行, lng_読み込み列).Value = var_取得値
                End If
                On Error GoTo ERR_HANDLER ' 標準エラーハンドラに戻す
                
            Next lng_読み込み列
            
            ' 回答ブックを閉じる
            wb_回答ブック.Close SaveChanges:=False
            
            ' 次の書き込み行に移動する
            lng_書き込み行 = lng_書き込み行 + 1
        End If
        
        ' 次のファイルを取得する
        str_ファイル名 = Dir()
    Loop
    
    ' 処理を完了する
    Application.ScreenUpdating = True
    ws_回答収集.Activate
    ws_回答収集.Cells(1, 1).Select
    
    MsgBox "回答の収集が完了しました。", vbInformation
    Exit Sub

ERR_HANDLER:
    ' エラー処理
    Application.ScreenUpdating = True
    Application.DisplayAlerts = True
    
    Dim str_エラーメッセージ As String
    str_エラーメッセージ = "エラーが発生しました。" & vbCrLf & vbCrLf & _
                          "エラー番号: " & Err.Number & vbCrLf & _
                          "エラー内容: " & Err.Description & vbCrLf & vbCrLf & _
                          "処理を中断します。"
    
    MsgBox str_エラーメッセージ, vbCritical, "エラー"
    
    ' 開いているブックがあれば閉じる(処理中断時にファイルを開きっぱなしにしないため)
    On Error Resume Next
    If Not wb_回答ブック Is Nothing Then
        wb_回答ブック.Close SaveChanges:=False
    End If
    On Error GoTo 0
End Sub
コードのポイント解説
1. フォルダ選択ダイアログ
Application.FileDialog(msoFileDialogFolderPicker) を使うことで、ユーザーに視覚的にフォルダを選択してもらうことができます。

Set fld_ダイアログ = Application.FileDialog(msoFileDialogFolderPicker)
If fld_ダイアログ.Show = False Then Exit Sub ' キャンセル時
str_フォルダパス = fld_ダイアログ.SelectedItems(1) & Application.PathSeparator
2. フォルダ内のファイル巡回
Dir関数を使って、指定したフォルダ内のExcelファイル(.xls*)を順番に処理します。

str_ファイル名 = Dir(str_フォルダパス & "*.xls*")
Do While str_ファイル名 <> ""
    ' ... ファイル処理 ...
    str_ファイル名 = Dir() ' 次のファイルを取得
Loop
3. 動的なエラーハンドリング
このツールの肝です。回答ブック側に「指定したシート名が存在しない」「セル番地が間違っている」といった不備があっても、マクロがエラーで停止しないように制御しています。

値を取得する直前で On Error Resume Next を宣言し、エラーを意図的に無視させます。
値の取得が終わったら、Err.Number をチェックしてエラーが発生していたか(0以外か)を判定し、発生していた場合は setting シートで指定したエラー表示(例: "取得失敗")を書き込んでいます。

' セルの値を取得する(エラーハンドリング付き)
On Error Resume Next
var_取得値 = wb_回答ブック.Worksheets(str_読み込みシート).Range(str_読み込みセル).Value

If Err.Number <> 0 Then
    ws_回答収集.Cells(lng_読み込み行, lng_書き込み列).Value = str_エラー時表示
    Err.Clear
Else
    ws_回答収集.Cells(lng_読み込み行, lng_書き込み列).Value = var_取得値
End If
' ★標準のエラーハンドラに戻す(忘れると全てのエラーが無視される)
On Error GoTo ERR_HANDLER 

おわりに
単純なコピペ作業はVBAに任せて、人間は採点や分析といった本来の業務に集中しましょう。
自由記述式のテスト採点や、アンケート集計などでぜひご活用ください。

おまけで縦書式の場合も掲載します。

Option Explicit
'==========================================================
' モジュール名:mod_回答収集
' 機能概要  :複数のExcelブックから回答を収集し、比較表を作成する
'==========================================================

'----------------------------------------------------------
' run_Settingシート初期作成
' 機能概要 : 本ツールで参照する設定値を管理する「setting」シートを作成する
' 引数  : なし
' 戻り値 : なし
' YYYY/MM/DD 名前
'----------------------------------------------------------
Public Sub run_Settingシート初期作成()
    On Error GoTo ERR_HANDLER
    
    Dim ws_設定 As Worksheet
    Dim bln_存在チェック As Boolean
    Dim obj_シート As Object

    ' settingシートの存在をチェックする
    bln_存在チェック = False
    For Each obj_シート In ThisWorkbook.Worksheets
        If obj_シート.Name = "setting" Then
            bln_存在チェック = True
            Exit For
        End If
    Next obj_シート

    ' 存在しない場合のみシートを作成する
    If bln_存在チェック = False Then
        Set ws_設定 = ThisWorkbook.Worksheets.Add(Before:=ThisWorkbook.Worksheets(1))
        ws_設定.Name = "setting"

        ' 設定項目のヘッダーとデフォルト値を書き込む
        With ws_設定
            .Range("A1").Value = "設定項目"
            .Range("B1").Value = "値"
            .Range("C1").Value = "説明"
            
            .Range("A2").Value = "回答収集シート名"
            .Range("B2").Value = "回答収集"
            .Range("C2").Value = "回答を収集・集計するシートの名前"

            .Range("A3").Value = "見出し列番号"
            .Range("B3").Value = 2
            .Range("C3").Value = "見出しが記載されている列番号(B=2)"
            
            .Range("A4").Value = "データ開始列番号"
            .Range("B4").Value = 3
            .Range("C4").Value = "回答データが開始する列番号(C=3)"
            
            .Range("A5").Value = "回答書き込み開始行"
            .Range("B5").Value = 3
            .Range("C5").Value = "実際の回答内容を書き込む先頭行番号(3行目から書き込み)"
            
            .Range("A6").Value = "エラー時表示"
            .Range("B6").Value = "取得失敗"
            .Range("C6").Value = "データ取得エラー時に表示する文字列"

            .Range("A7").Value = "解説列番号"
            .Range("B7").Value = 1 ' デフォルト値: A列
            .Range("C7").Value = "解説や質問項目の列番号(A=1)"

            ' 見た目を調整する
            .Columns("A:B").AutoFit
            .Range("A1:B1").Font.Bold = True
        End With
        
        MsgBox "「setting」シートを作成しました。初期設定を確認してください。", vbInformation
    End If
    Exit Sub

ERR_HANDLER:
    ' エラー処理を行う
    Application.ScreenUpdating = True
    Application.DisplayAlerts = True
    
    MsgBox "設定シートの作成中にエラーが発生しました。" & vbCrLf & vbCrLf & _
           "エラー番号: " & Err.Number & vbCrLf & _
           "エラー内容: " & Err.Description, vbCritical, "エラー"
End Sub

'----------------------------------------------------------
' main_回答収集実行
' 機能概要 : 指定フォルダ内の全Excelブックから回答を収集し、比較表を作成する
' 引数  : なし
' 戻り値 : なし
' YYYY/MM/DD 名前
'----------------------------------------------------------
Public Sub main_回答収集実行()
    On Error GoTo ERR_HANDLER
    
    ' 定数を宣言する
    Const STR_設定シート名 As String = "setting"
    
    ' オブジェクト変数を宣言する
    Dim ws_設定 As Worksheet
    Dim ws_回答収集 As Worksheet
    Dim wb_回答ブック As Workbook
    Dim fld_ダイアログ As FileDialog
    
    ' 設定値を格納する変数を宣言する
    Dim str_回答収集シート名 As String
    Dim lng_見出し列 As Long
    Dim lng_データ開始列 As Long
    Dim lng_書き込み開始行 As Long
    Dim str_エラー時表示 As String
    
    ' 処理用変数を宣言する
    Dim str_フォルダパス As String
    Dim str_ファイル名 As String
    Dim lng_書き込み行 As Long
    Dim lng_読み込み列 As Long
    Dim lng_最終列 As Long
    Dim str_読み込みシート As String
    Dim str_読み込みセル As String
    Dim var_取得値 As Variant
    
    ' settingシートの存在を確認する
    On Error Resume Next
    Set ws_設定 = ThisWorkbook.Worksheets(STR_設定シート名)
    If Err.Number <> 0 Then
        On Error GoTo 0
        MsgBox "「setting」シートが見つかりません。" & vbCrLf & _
               "「run_Settingシート初期作成」を実行してシートを作成してください。", vbCritical
        Exit Sub
    End If
    On Error GoTo ERR_HANDLER ' ここで標準エラーハンドラに戻す

    ' 設定値をsettingシートから読み込む
    With ws_設定
        str_回答収集シート名 = .Range("B2").Value
        lng_見出し列 = .Range("B3").Value
        lng_データ開始列 = .Range("B4").Value
        lng_書き込み開始行 = .Range("B5").Value
        str_エラー時表示 = .Range("B6").Value
    End With
    
    ' 回答収集シートの存在をチェックする
    On Error Resume Next
    Set ws_回答収集 = ThisWorkbook.Worksheets(str_回答収集シート名)
    If Err.Number <> 0 Then
        On Error GoTo 0
        MsgBox "設定シートで指定された「" & str_回答収集シート名 & "」シートが見つかりません。", vbCritical
        Exit Sub
    End If
    On Error GoTo ERR_HANDLER ' 標準エラーハンドラに戻す
    
    ' フォルダ選択ダイアログを表示する
    Set fld_ダイアログ = Application.FileDialog(msoFileDialogFolderPicker)
    fld_ダイアログ.Title = "回答ファイルが保存されているフォルダを選択してください"
    If fld_ダイアログ.Show = False Then
        MsgBox "処理がキャンセルされました。", vbInformation
        Exit Sub
    End If
    str_フォルダパス = fld_ダイアログ.SelectedItems(1) & Application.PathSeparator

    ' 画面更新を停止して既存データをクリアする
    Application.ScreenUpdating = False
    
    With ws_回答収集
        .Range(.Cells(lng_書き込み開始行, lng_データ開始列), .Cells(.Rows.Count, .Columns.Count)).ClearContents
    End With
    
    ' ファイル巡回処理を開始する
    lng_書き込み行 = lng_書き込み開始行
    str_ファイル名 = Dir(str_フォルダパス & "*.xls*")
    
    Do While str_ファイル名 <> ""
        ' 自分自身のブックを除外する
        If str_ファイル名 <> ThisWorkbook.Name Then
            
            ' 回答ブックを読み取り専用で開く
            Set wb_回答ブック = Workbooks.Open(str_フォルダパス & str_ファイル名, ReadOnly:=True)
            
            ' 見出し列にブック名を書き込む
            ws_回答収集.Cells(lng_書き込み行, lng_見出し列).Value = wb_回答ブック.Name
            
            ' 収集シートのA列を基準に列を巡回する
            lng_最終列 = ws_回答収集.Cells(1, ws_回答収集.Columns.Count).End(xlToLeft).Column
            
            For lng_読み込み列 = lng_データ開始列 To lng_最終列
                str_読み込みシート = ws_回答収集.Cells(1, lng_読み込み列).Value
                str_読み込みセル = ws_回答収集.Cells(2, lng_読み込み列).Value
                
                ' セルの値を取得する(エラーハンドリング付き)
                On Error Resume Next
                var_取得値 = wb_回答ブック.Worksheets(str_読み込みシート).Range(str_読み込みセル).Value
                
                If Err.Number <> 0 Then
                    ws_回答収集.Cells(lng_書き込み行, lng_読み込み列).Value = str_エラー時表示
                    Err.Clear
                Else
                    ws_回答収集.Cells(lng_書き込み行, lng_読み込み列).Value = var_取得値
                End If
                On Error GoTo ERR_HANDLER ' 標準エラーハンドラに戻す
                
            Next lng_読み込み列
            
            ' 回答ブックを閉じる
            wb_回答ブック.Close SaveChanges:=False
            
            ' 次の書き込み行に移動する
            lng_書き込み行 = lng_書き込み行 + 1
        End If
        
        ' 次のファイルを取得する
        str_ファイル名 = Dir()
    Loop
    
    ' 処理を完了する
    Application.ScreenUpdating = True
    ws_回答収集.Activate
    ws_回答収集.Cells(1, 1).Select
    
    MsgBox "回答の収集が完了しました。", vbInformation
    Exit Sub

ERR_HANDLER:
    ' エラー処理
    Application.ScreenUpdating = True
    Application.DisplayAlerts = True
    
    Dim str_エラーメッセージ As String
    str_エラーメッセージ = "エラーが発生しました。" & vbCrLf & vbCrLf & _
                          "エラー番号: " & Err.Number & vbCrLf & _
                          "エラー内容: " & Err.Description & vbCrLf & vbCrLf & _
                          "処理を中断します。"
    
    MsgBox str_エラーメッセージ, vbCritical, "エラー"
    
    ' 開いているブックがあれば閉じる(処理中断時にファイルを開きっぱなしにしないため)
    On Error Resume Next
    If Not wb_回答ブック Is Nothing Then
        wb_回答ブック.Close SaveChanges:=False
    End If
    On Error GoTo 0
End Sub



0
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
0
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?