VBAで自動化 VBA一覧 セル・値の取得と貼り付け 取得

【VBA】別シートのセルの値を取得する方法|ループ処理で安全かつ再利用しやすい実務設計

Excel VBAで別シートのセルの値を取得したい場面は、実務では非常によくあります。たとえば、入力用シートにあるデータを集計用シートへ転記したり、一覧表から条件に合う値だけを取得したり、複数行のデータを順番に読み取って別シートへ反映したりするケースです。

ただ、別シートのセルを取得する処理は、書き方を間違えると「どのシートを見ているのか分からない」「行数が変わると動かない」「後から列を変更しにくい」といった問題が起きやすい部分でもあります。特にループ処理と組み合わせる場合、最初は動いていても、データ量が増えたときやシート構成が変わったときに不具合が出ることがあります。

この記事では、VBAで別シートのセルの値をループ処理で取得する基本から、実務で使いやすい書き方、注意点、応用パターンまで解説します。

目次

✅ VBAで別シートのセル値を取得する基本

別シートのセル値を取得するときに大切なのは、「どのブックの、どのシートの、どのセルを参照しているのか」を明確にすることです。ここを曖昧にしたままコードを書くと、アクティブシートが変わっただけで意図しないシートから値を取得してしまうことがあります。実務では、処理中に別シートを開いたり、ユーザーが別のシートを選択していたりすることも珍しくありません。そのため、VBAではできるだけActiveSheetに頼らず、シートを変数に入れて明示的に扱うことが重要です。また、ループ処理を行う前に、取得元シートと出力先シートを分けて考えると、後から修正しやすいコードになります。最初にこの基本を押さえておくと、行数が増えた場合や列を変更したい場合にも対応しやすくなります。

・別シートのセルを直接指定して取得する基本形

別シートのセル値は、次のようにシート名とセル番地を指定して取得できます。

Sub GetValueFromAnotherSheet()

    Dim sourceValue As Variant

    sourceValue = ThisWorkbook.Worksheets("入力").Range("A2").Value

    MsgBox sourceValue

End Sub

このコードでは、「入力」シートのA2セルの値を取得し、メッセージボックスに表示しています。

ポイントは、Worksheets("入力")のようにシート名を明示していることです。

Range("A2").Value

だけで書くと、現在アクティブなシートのA2セルを参照してしまいます。
一方で、

ThisWorkbook.Worksheets("入力").Range("A2").Value

と書けば、このマクロが保存されているブックの「入力」シートのA2セルを取得する、という意味が明確になります。

・シートを変数に入れて扱うと実務で読みやすい

実務では、毎回ThisWorkbook.Worksheets("入力")と書くよりも、最初にシートを変数へ入れておく方が読みやすくなります。

Sub GetValueUsingWorksheetVariable()

    Dim sourceSheet As Worksheet
    Dim sourceValue As Variant

    Set sourceSheet = ThisWorkbook.Worksheets("入力")

    sourceValue = sourceSheet.Range("A2").Value

    MsgBox sourceValue

End Sub

この書き方にしておくと、コードの中で「取得元はsourceSheet」という意味がはっきりします。

また、後からシート名が変更になった場合も、修正箇所を最小限にできます。
たとえば「入力」シートが「データ入力」に変わった場合でも、Set sourceSheet = ...の部分だけを直せば済みます。

・別シート取得でActiveSheetを避けるべき理由

別シートの値を取得する処理で、次のような書き方は避けた方が安全です。

Sub BadExample()

    Dim sourceValue As Variant

    Worksheets("入力").Activate
    sourceValue = Range("A2").Value

    MsgBox sourceValue

End Sub

一見すると動きますが、実務ではあまりおすすめできません。
理由は、処理の途中でアクティブシートを切り替えているため、コードの流れが分かりにくくなるからです。

また、画面がチラついたり、処理速度が落ちたりする原因にもなります。
VBAでは、シートを選択しなくてもセルの値は取得できます。

そのため、次のように直接指定する方が安全です。

sourceValue = sourceSheet.Range("A2").Value

「シートを選択してから取得する」のではなく、
「取得したいシートを明示して直接値を取得する」
という考え方が、実務では基本になります。

別シートのセル値を取得する処理では、アクティブシートに依存しない書き方が重要です。Range("A1")だけで指定した場合にどのシートを参照するのか不安がある場合は、アクティブセルやアクティブシートの基本を整理した「【VBA】アクティブセル・アクティブシートの考え方と安全な指定方法」もあわせて確認しておくと、シート指定のミスを防ぎやすくなります。

✅ VBAでループ処理を使って別シートの値を順番に取得する

別シートのセル値を1つだけ取得するなら、セル番地を直接指定すれば十分です。しかし、実務で多いのは、一覧表のように複数行のデータを順番に取得するケースです。たとえば、A列に社員番号、B列に氏名、C列に部署名が並んでいて、それを1行ずつ読み取るような処理です。このときにループ処理を使うと、同じ処理を何度も書かずに済みます。ただし、ループ範囲を固定してしまうと、データが増減したときに対応できません。そのため、最終行を取得してからループする設計にしておくことが重要です。ここを押さえておくと、実務データのように行数が日々変わる表でも安定して処理できます。

・For文で別シートの値を1行ずつ取得する基本コード

次のコードは、「入力」シートのA列にある値を2行目から最終行まで順番に取得する例です。

Sub GetValuesByLoop()

    Dim sourceSheet As Worksheet
    Dim lastRow As Long
    Dim currentRow As Long
    Dim employeeName As Variant

    '取得元シートを明確に指定する
    Set sourceSheet = ThisWorkbook.Worksheets("入力")

    'A列を基準に最終行を取得する
    lastRow = sourceSheet.Cells(sourceSheet.Rows.Count, "A").End(xlUp).Row

    '2行目から最終行まで順番に値を取得する
    For currentRow = 2 To lastRow

        employeeName = sourceSheet.Cells(currentRow, "A").Value

        Debug.Print employeeName

    Next currentRow

End Sub

このコードでは、A列の2行目から最終行までを順番に読み取り、取得した値をイミディエイトウィンドウへ出力しています。

実務では、1行目を見出しにして、2行目以降をデータとして扱うことが多いため、For currentRow = 2 To lastRowとしています。

・なぜ最終行を取得してからループするのか

ループ処理では、次のように行数を固定して書くこともできます。

For currentRow = 2 To 100

しかし、この書き方だと、データが100行より少ない場合は空白行まで処理してしまいます。
逆に、データが100行を超えた場合は、101行目以降が処理されません。

実務では、毎回同じ件数のデータを扱うとは限りません。
そのため、最終行を自動で取得してからループする方が安全です。

lastRow = sourceSheet.Cells(sourceSheet.Rows.Count, "A").End(xlUp).Row

この処理では、A列の一番下から上方向に見て、最後に値が入っている行を取得しています。
つまり、A列にデータが追加されても、ループ範囲が自動で変わります。

・Cellsを使うとループ処理と相性が良い

ループ処理では、Range("A2")よりもCells(行番号, 列番号)の方が扱いやすいです。

たとえば、A列の値を行番号で取得したい場合は、次のように書けます。

sourceSheet.Cells(currentRow, "A").Value

currentRowの値が2ならA2、3ならA3、4ならA4を取得します。

このように、行番号を変数で管理できるため、ループ処理と相性が良いです。
列も数字で指定できますが、実務では"A""B"のように列記号で書くと読みやすい場合があります。

sourceSheet.Cells(currentRow, "A").Value
sourceSheet.Cells(currentRow, "B").Value
sourceSheet.Cells(currentRow, "C").Value

どの列を取得しているかが視覚的に分かりやすくなるため、記事や引き継ぎ用のコードでは特に有効です。

別シートの値をループで取得するときは、どこまで処理するかを決めるために「最終行の取得」が重要になります。Rows.Countを使った最終行取得や、行全体・複数行の指定方法を整理しておきたい場合は、「【VBA】Rowsの基本的な使い方|行指定・複数行・最終行取得まで解説」もあわせて確認しておくと、ループ処理の範囲指定で迷いにくくなります。

✅ VBAで別シートから複数列の値を取得する実務例

実務では、1列だけでなく複数列の値をまとめて取得することが多くあります。社員番号、氏名、部署、金額、日付など、1行に複数の情報が並んでいる表を扱うケースです。このとき、列ごとに意味のある変数名を付けて取得すると、後からコードを読んだときに処理内容が分かりやすくなります。逆に、abのような変数名を使うと、何の値を取得しているのか分からなくなり、修正時にミスが起きやすくなります。また、取得する列が増えるほど、処理の目的をコメントで補足しておくことが重要です。単に動くだけではなく、後から見ても「何のために取得しているのか」が分かる構成にすることが、実務向けのVBAでは大切です。

・社員一覧から複数列の値を取得するコード例

次の例では、「入力」シートにある社員一覧から、社員番号・氏名・部署名を1行ずつ取得します。

Sub GetMultipleValuesFromAnotherSheet()

    Dim sourceSheet As Worksheet
    Dim lastRow As Long
    Dim currentRow As Long

    Dim employeeId As Variant
    Dim employeeName As Variant
    Dim departmentName As Variant

    '取得元となる社員一覧シートを指定する
    Set sourceSheet = ThisWorkbook.Worksheets("入力")

    '社員番号が入っているA列を基準に最終行を取得する
    lastRow = sourceSheet.Cells(sourceSheet.Rows.Count, "A").End(xlUp).Row

    '2行目以降の社員データを1行ずつ取得する
    For currentRow = 2 To lastRow

        employeeId = sourceSheet.Cells(currentRow, "A").Value
        employeeName = sourceSheet.Cells(currentRow, "B").Value
        departmentName = sourceSheet.Cells(currentRow, "C").Value

        Debug.Print employeeId & " / " & employeeName & " / " & departmentName

    Next currentRow

End Sub

このコードでは、各列の値を意味のある変数に格納しています。

  • employeeId:社員番号
  • employeeName:氏名
  • departmentName:部署名

このように変数名を具体的にすると、後からコードを見たときに、どの値を扱っているのかが分かりやすくなります。

・列番号を直接書きすぎない工夫

コードが短い場合は、"A""B""C"と直接書いても問題ありません。
ただし、実務で列数が増える場合や、列位置が変更される可能性がある場合は、列番号を定数として管理すると修正しやすくなります。

Sub GetMultipleValuesUsingConstants()

    Const COL_EMPLOYEE_ID As String = "A"
    Const COL_EMPLOYEE_NAME As String = "B"
    Const COL_DEPARTMENT_NAME As String = "C"

    Dim sourceSheet As Worksheet
    Dim lastRow As Long
    Dim currentRow As Long

    Dim employeeId As Variant
    Dim employeeName As Variant
    Dim departmentName As Variant

    Set sourceSheet = ThisWorkbook.Worksheets("入力")

    lastRow = sourceSheet.Cells(sourceSheet.Rows.Count, COL_EMPLOYEE_ID).End(xlUp).Row

    For currentRow = 2 To lastRow

        employeeId = sourceSheet.Cells(currentRow, COL_EMPLOYEE_ID).Value
        employeeName = sourceSheet.Cells(currentRow, COL_EMPLOYEE_NAME).Value
        departmentName = sourceSheet.Cells(currentRow, COL_DEPARTMENT_NAME).Value

        Debug.Print employeeId & " / " & employeeName & " / " & departmentName

    Next currentRow

End Sub

この書き方にしておくと、列が変更されたときに定数部分だけを修正すれば済みます。

たとえば、氏名がB列からD列に移動した場合でも、

Const COL_EMPLOYEE_NAME As String = "D"

に変更するだけです。

コード内に何度も"B"が出てくる状態だと、修正漏れが起きやすくなります。
定数化しておくことで、保守性が高くなります。

・この書き方が実務で扱いやすい理由

実務で使うVBAは、一度作って終わりではありません。
後から列が追加されたり、見出し名が変わったり、取得条件が増えたりすることがあります。

そのため、最初から変更しやすい構成にしておくことが大切です。

今回のコードでは、次の点を意識しています。

  • 取得元シートを変数で管理する
  • 最終行を自動で取得する
  • 列位置を定数で管理する
  • 取得した値を意味のある変数名に入れる
  • 処理の目的が分かるコメントを入れる

このようにしておくと、半年後にコードを見返したときでも内容を理解しやすくなります。
また、他の人に引き継ぐ場合にも、「どこを変更すればよいか」が分かりやすくなります。

✅ VBAで別シートの値を取得して別シートへ貼り付ける方法

別シートから値を取得する処理は、取得だけで終わることは少なく、多くの場合は別のシートへ貼り付けたり、加工して出力したりします。たとえば、入力シートから必要な情報だけを取り出して、一覧シートや集計シートへ転記する処理です。このとき、取得元シートと出力先シートを明確に分けておかないと、どちらのシートを操作しているのか分かりにくくなります。また、取得と貼り付けを同じループ内で行う場合、行番号の管理が重要になります。入力側の行番号と出力側の行番号が必ず同じとは限らないためです。ここを丁寧に設計しておくと、条件付き転記やデータ抽出にも応用しやすくなります。

・別シートから取得した値を出力シートへ転記するコード

次の例では、「入力」シートのA列からC列の値を取得し、「出力」シートへ転記します。

Sub CopyValuesToAnotherSheetByLoop()

    Const COL_EMPLOYEE_ID As String = "A"
    Const COL_EMPLOYEE_NAME As String = "B"
    Const COL_DEPARTMENT_NAME As String = "C"

    Dim sourceSheet As Worksheet
    Dim outputSheet As Worksheet

    Dim lastRow As Long
    Dim currentRow As Long
    Dim outputRow As Long

    Dim employeeId As Variant
    Dim employeeName As Variant
    Dim departmentName As Variant

    '取得元シートと出力先シートを明確に分けて指定する
    Set sourceSheet = ThisWorkbook.Worksheets("入力")
    Set outputSheet = ThisWorkbook.Worksheets("出力")

    '出力先を初期化する
    outputSheet.Range("A2:C" & outputSheet.Rows.Count).ClearContents

    '取得元の最終行を取得する
    lastRow = sourceSheet.Cells(sourceSheet.Rows.Count, COL_EMPLOYEE_ID).End(xlUp).Row

    '出力先は2行目から開始する
    outputRow = 2

    For currentRow = 2 To lastRow

        employeeId = sourceSheet.Cells(currentRow, COL_EMPLOYEE_ID).Value
        employeeName = sourceSheet.Cells(currentRow, COL_EMPLOYEE_NAME).Value
        departmentName = sourceSheet.Cells(currentRow, COL_DEPARTMENT_NAME).Value

        outputSheet.Cells(outputRow, "A").Value = employeeId
        outputSheet.Cells(outputRow, "B").Value = employeeName
        outputSheet.Cells(outputRow, "C").Value = departmentName

        outputRow = outputRow + 1

    Next currentRow

End Sub

このコードでは、取得元の行番号をcurrentRow、出力先の行番号をoutputRowとして分けています。

同じ行番号を使っても動くケースはありますが、実務では分けておく方が安全です。

・取得元行と出力先行を分けるメリット

たとえば、すべての行を転記するだけなら、取得元も出力先も2行目から始まるため、同じ行番号でも処理できます。

しかし、次のような処理になると、行番号を分ける必要があります。

  • 条件に合う行だけ出力する
  • 空白行を除外して出力する
  • エラーのある行はスキップする
  • 並べ替え用に別の順番で出力する

たとえば、入力シートの5行目が条件に合わず出力しない場合、出力先では行を詰める必要があります。
このとき、取得元のcurrentRowと出力先のoutputRowを分けていないと、空白行ができたり、意図しない位置に貼り付けたりする可能性があります。

そのため、最初から次のように役割を分けておくと安全です。

  • currentRow:入力シートを読むための行番号
  • outputRow:出力シートへ書き込むための行番号

この設計にしておくと、後から条件付き転記へ変更しやすくなります。

・出力先を初期化してから貼り付ける理由

コード内では、次の処理で出力先を初期化しています。

outputSheet.Range("A2:C" & outputSheet.Rows.Count).ClearContents

これは、前回実行時のデータが残るのを防ぐためです。

たとえば、前回は100行出力され、今回は80行しか出力されなかった場合、初期化しないと81行目以降に古いデータが残ってしまいます。

実務では、この「前回データの残り」が非常に厄介です。
見た目では気づきにくく、集計ミスや確認ミスにつながることがあります。

そのため、出力処理を行う前には、必要な範囲をクリアしてから新しいデータを書き込むのが安全です。

ただし、出力先に数式や書式が入っている場合は、ClearContentsの範囲を慎重に指定する必要があります。
値だけ消したいのか、書式も含めて消したいのかによって、使うメソッドを分けましょう。

別シートから取得した値をそのまま転記する処理は、データ件数が増えると処理時間が長くなることがあります。大量データを扱う場合は、セルを1つずつ読み取るのではなく、配列へまとめて取得してから処理する設計にすると効率的です。ループ処理をさらに高速かつ安定して実行したい場合は、「【VBA】セルの値を変数配列に取得:ループ処理を実務で使いこなす方法」もあわせて確認しておくと安心です。

✅ VBAで条件に合う別シートの値だけをループで取得する

実務では、別シートの値をすべて取得するよりも、条件に合うデータだけを取得したいケースが多くあります。たとえば、部署が「営業部」の社員だけを抽出したい、ステータスが「完了」の行だけを転記したい、金額が0より大きいデータだけを集計したい、といった場面です。このような処理では、ループの中で条件判定を行い、条件に合う場合だけ取得・出力する構成にします。ただし、条件をコード内に直接書きすぎると、後から変更しにくくなります。そのため、条件値を定数や変数で管理しておくと、実務で扱いやすくなります。条件付き処理は便利ですが、空白や表記ゆれにも注意が必要です。

・営業部のデータだけを取得して出力するコード例

次の例では、「入力」シートの部署名が「営業部」の行だけを取得し、「出力」シートへ転記します。

Sub ExtractValuesByCondition()

    Const COL_EMPLOYEE_ID As String = "A"
    Const COL_EMPLOYEE_NAME As String = "B"
    Const COL_DEPARTMENT_NAME As String = "C"
    Const TARGET_DEPARTMENT As String = "営業部"

    Dim sourceSheet As Worksheet
    Dim outputSheet As Worksheet

    Dim lastRow As Long
    Dim currentRow As Long
    Dim outputRow As Long

    Dim employeeId As Variant
    Dim employeeName As Variant
    Dim departmentName As String

    Set sourceSheet = ThisWorkbook.Worksheets("入力")
    Set outputSheet = ThisWorkbook.Worksheets("出力")

    outputSheet.Range("A2:C" & outputSheet.Rows.Count).ClearContents

    lastRow = sourceSheet.Cells(sourceSheet.Rows.Count, COL_EMPLOYEE_ID).End(xlUp).Row
    outputRow = 2

    For currentRow = 2 To lastRow

        employeeId = sourceSheet.Cells(currentRow, COL_EMPLOYEE_ID).Value
        employeeName = sourceSheet.Cells(currentRow, COL_EMPLOYEE_NAME).Value
        departmentName = CStr(sourceSheet.Cells(currentRow, COL_DEPARTMENT_NAME).Value)

        '対象部署のデータだけを出力する
        If departmentName = TARGET_DEPARTMENT Then

            outputSheet.Cells(outputRow, "A").Value = employeeId
            outputSheet.Cells(outputRow, "B").Value = employeeName
            outputSheet.Cells(outputRow, "C").Value = departmentName

            outputRow = outputRow + 1

        End If

    Next currentRow

End Sub

このコードでは、TARGET_DEPARTMENTという定数で抽出条件を管理しています。

Const TARGET_DEPARTMENT As String = "営業部"

こうしておくと、対象部署を「経理部」に変えたい場合でも、修正箇所が分かりやすくなります。

・条件値を定数化すると修正に強くなる

条件付きのループ処理でよくある失敗は、条件値をコードのあちこちに直接書いてしまうことです。

If departmentName = "営業部" Then

このように1か所だけなら問題ありません。
しかし、同じ条件を複数箇所で使う場合、後から条件を変更すると修正漏れが起きやすくなります。

そのため、条件値は定数として管理すると安全です。

Const TARGET_DEPARTMENT As String = "営業部"

条件値に名前を付けることで、「この処理は営業部を対象にしている」という意図も伝わりやすくなります。

VBAでは、単に短く書くことよりも、後から読んで意味が分かることが重要です。
特に業務用マクロでは、作成者本人以外が修正する可能性もあります。

・空白や余分なスペースに注意する

条件判定では、見た目は同じでも一致しないケースがあります。
たとえば、セルに次のような値が入っている場合です。

  • 営業部
  • 営業部
  • 営業部

人間の目ではほとんど同じに見えますが、VBAでは別の文字列として判定されます。

そのため、実務ではTrim関数を使って前後のスペースを取り除いてから比較することもあります。

departmentName = Trim(CStr(sourceSheet.Cells(currentRow, COL_DEPARTMENT_NAME).Value))

このようにしておくと、前後に余分なスペースが入っていても、条件判定の失敗を減らせます。

ただし、すべてのケースで自動的に整形すればよいわけではありません。
コードで吸収するべき問題なのか、元データの入力ルールを見直すべき問題なのかも考える必要があります。

条件に合うデータだけを取得する処理では、見た目は同じでも前後にスペースが含まれていることで一致判定に失敗するケースがあります。特に外部データや手入力データでは、全角・半角・改行などの余分な文字が混ざっていることも少なくありません。こうした文字の影響を取り除いて正確に条件判定を行いたい場合は、「【VBA】シート全体のスペースを削除する方法|全角・半角・改行まで実務で完全対策」もあわせて確認しておくと安心です。

✅ VBAで別シートのセル値を取得するときのエラー対策

別シートの値を取得する処理では、シート名の変更、空白データ、想定外の値、最終行の誤判定などが原因でエラーや不具合が起きることがあります。特に実務では、利用者がシート名を変更したり、見出しだけ残してデータが空になったりすることもあります。コード作成時に正常データだけを前提にしていると、少しの変更で処理が止まってしまいます。そのため、別シート取得のVBAでは、最低限のチェック処理を入れておくことが重要です。エラー対策はコードを長くするため面倒に見えますが、実務ではトラブル対応の時間を減らす効果があります。処理が止まったときに原因が分かるよう、メッセージも分かりやすくしておくと安心です。

・対象シートが存在しない場合に備える考え方

次のようにシート名を直接指定している場合、シートが存在しないとエラーになります。

Set sourceSheet = ThisWorkbook.Worksheets("入力")

実務では、シート名が変更されたり、誤って削除されたりする可能性があります。
そのため、シートが存在するか確認する関数を用意しておくと安全です。

Function WorksheetExists(ByVal targetSheetName As String) As Boolean

    Dim checkSheet As Worksheet

    WorksheetExists = False

    For Each checkSheet In ThisWorkbook.Worksheets

        If checkSheet.Name = targetSheetName Then
            WorksheetExists = True
            Exit Function
        End If

    Next checkSheet

End Function

この関数は、指定した名前のシートが存在するかを確認します。

・シート存在チェックを使った安全な取得コード

先ほどの関数を使うと、次のように安全に処理できます。

Sub GetValuesWithSheetCheck()

    Const SOURCE_SHEET_NAME As String = "入力"

    Dim sourceSheet As Worksheet
    Dim lastRow As Long
    Dim currentRow As Long
    Dim targetValue As Variant

    '取得元シートが存在するか確認する
    If WorksheetExists(SOURCE_SHEET_NAME) = False Then
        MsgBox "取得元シート「" & SOURCE_SHEET_NAME & "」が見つかりません。", vbExclamation
        Exit Sub
    End If

    Set sourceSheet = ThisWorkbook.Worksheets(SOURCE_SHEET_NAME)

    lastRow = sourceSheet.Cells(sourceSheet.Rows.Count, "A").End(xlUp).Row

    If lastRow < 2 Then
        MsgBox "取得対象のデータがありません。", vbInformation
        Exit Sub
    End If

    For currentRow = 2 To lastRow

        targetValue = sourceSheet.Cells(currentRow, "A").Value
        Debug.Print targetValue

    Next currentRow

End Sub

このコードでは、次の2つを確認しています。

  • 「入力」シートが存在するか
  • 2行目以降にデータがあるか

このようにチェックを入れておくと、処理が突然止まるのではなく、原因をメッセージで伝えられます。

・On Error Resume Nextに頼りすぎない

VBAでは、エラーを回避するためにOn Error Resume Nextを使うことがあります。
ただし、実務では安易に使いすぎない方が安全です。

On Error Resume Nextは、エラーが発生しても次の処理へ進む命令です。
便利ではありますが、原因を見逃したまま処理が続いてしまう危険があります。

特に、別シートから値を取得する処理では、取得に失敗しているのに空白のまま出力されるような不具合につながることがあります。

そのため、次のような考え方がおすすめです。

  • 想定できる問題は事前にチェックする
  • シート存在確認やデータ有無確認を入れる
  • エラーを無視するのではなく、原因が分かる形で止める
  • 必要な場面だけ限定的にエラー制御を使う

エラーを隠すよりも、原因を早く見つけられる設計にする方が、長期的には安全です。

エラー対策として、On Error Resume Nextを使って処理を継続させる方法が紹介されることもありますが、原因を特定できないまま処理が進んでしまうため、実務では慎重に扱う必要があります。安易にエラーを無視することで起こりやすいトラブルや、安全にエラーを制御する考え方を整理しておきたい場合は、「【VBA】On Error Resume Nextでエラーを無視してエラーの制御|危険な理由」もあわせて確認しておくと安心です。

✅ VBAで別シートの値取得を高速化する考え方

別シートのセル値をループで取得する処理は、データ件数が少ないうちは問題なく動きます。しかし、数千行、数万行のデータを扱うようになると、セルを1つずつ読み取る処理が遅くなることがあります。Excel VBAでは、ワークシート上のセルへ何度もアクセスする処理は比較的時間がかかります。そのため、大量データを扱う場合は、配列にまとめて取得してから処理する方法も検討するとよいです。ただし、最初から配列を使うとコードが少し分かりにくくなるため、記事の目的や読者レベルに合わせて使い分けることが大切です。ここでは、通常のループ処理と配列処理の考え方の違いを押さえておきましょう。

・セルを1つずつ読む処理が遅くなる理由

次のような処理は、行数が多いと遅くなることがあります。

For currentRow = 2 To lastRow
    employeeName = sourceSheet.Cells(currentRow, "B").Value
Next currentRow

これは、ループのたびにExcelシートへアクセスしているためです。

数百行程度なら問題ありませんが、数万行になると処理時間が気になることがあります。
実務では、毎日使うマクロほど処理速度が重要になります。

ただし、処理速度だけを優先して複雑なコードにすると、保守性が下がることもあります。
そのため、まずは分かりやすいループ処理で作り、データ量が多い場合に配列化を検討する流れが現実的です。

・大量データでは配列にまとめて取得する方法もある

次の例では、「入力」シートのA列からC列を配列にまとめて取得します。

Sub GetValuesUsingArray()

    Dim sourceSheet As Worksheet
    Dim lastRow As Long
    Dim sourceData As Variant
    Dim dataIndex As Long

    Dim employeeId As Variant
    Dim employeeName As Variant
    Dim departmentName As Variant

    Set sourceSheet = ThisWorkbook.Worksheets("入力")

    lastRow = sourceSheet.Cells(sourceSheet.Rows.Count, "A").End(xlUp).Row

    If lastRow < 2 Then
        MsgBox "取得対象のデータがありません。", vbInformation
        Exit Sub
    End If

    'A2:C最終行までをまとめて配列に取得する
    sourceData = sourceSheet.Range("A2:C" & lastRow).Value

    For dataIndex = 1 To UBound(sourceData, 1)

        employeeId = sourceData(dataIndex, 1)
        employeeName = sourceData(dataIndex, 2)
        departmentName = sourceData(dataIndex, 3)

        Debug.Print employeeId & " / " & employeeName & " / " & departmentName

    Next dataIndex

End Sub

配列に取得すると、シートへのアクセス回数を減らせます。
そのため、大量データでは処理速度が改善しやすくなります。

・最初から配列にしない方がよいケースもある

配列処理は高速ですが、初心者には少し分かりにくい面もあります。
特に、sourceData(dataIndex, 1)のように、列の意味が数字だけになると、何を取得しているのか分かりにくくなります。

そのため、次のように使い分けるとよいです。

  • 数百行程度なら、通常のループ処理で十分
  • 数千行以上で遅さを感じるなら、配列処理を検討
  • 保守性を優先するなら、列番号の意味をコメントや定数で補足
  • 読みやすさが重要な業務マクロでは、無理に高速化しすぎない

VBAでは、「速ければよい」というわけではありません。
業務で長く使うなら、処理速度と読みやすさのバランスが大切です。

✅ VBAで別シートの値取得を実務で使うときの注意点

別シートのセル値を取得する処理は、さまざまな業務に応用できますが、同時にトラブルも起きやすい部分です。特に、シート名、列位置、見出し行、空白セル、数式結果などは、後から問題になりやすいポイントです。最初にコードを書いたときは問題なく動いても、運用が始まるとデータの形式が少しずつ変わることがあります。その変化に耐えられるようにするには、コード内の前提条件を明確にしておくことが重要です。また、利用者がどのシートを編集するのか、どの列を変更してはいけないのかも整理しておくと、マクロの安定性が高まります。別シート取得の処理は小さな処理に見えますが、実務自動化の土台になる重要な部分です。

・シート名変更に弱いコードにしない

VBAでシート名を指定する場合、次のように名前で指定することが多いです。

Set sourceSheet = ThisWorkbook.Worksheets("入力")

この書き方は分かりやすい一方で、シート名が変わると動かなくなります。

実務で利用者がシート名を変更する可能性がある場合は、次のような対策を考えます。

  1. シート名を変更しない運用ルールにする
  2. シート存在チェックを入れる
  3. シート名を定数として管理する
  4. 必要に応じてコード名を使う設計にする

特に複数のマクロで同じシートを使う場合は、シート名を定数化しておくと修正しやすくなります。

・空白セルをどう扱うか事前に決める

別シートから値を取得するとき、空白セルがあると処理結果に影響することがあります。

たとえば、社員番号が空白の行をどう扱うかは、業務によって異なります。

  • 空白行としてスキップする
  • 入力漏れとしてエラーにする
  • そのまま空白で出力する
  • 後で確認できるようにログへ残す

この判断を曖昧にしたままコードを書くと、後から「なぜこの行が出力されていないのか分からない」という問題が起きます。

実務では、空白を単なるデータなしとして扱うのか、入力ミスとして扱うのかを先に決めておくことが大切です。

・数式セルの値を取得している点に注意する

VBAで.Valueを使うと、セルに数式が入っている場合は、数式そのものではなく計算結果を取得します。

たとえば、A2セルに次の数式が入っている場合です。

"=B2+C2"

.Valueで取得すると、数式ではなく計算結果が取得されます。

これは多くの実務では便利ですが、数式そのものを取得したい場合は.Formulaを使う必要があります。

targetFormula = sourceSheet.Range("A2").Formula

値を取得したいのか、数式を取得したいのかによって、使うプロパティが変わります。

別シート取得の記事では.Valueを使うことが多いですが、数式管理やチェック処理を行う場合は.Formulaも意識しておくとよいです。

✅ VBAで別シートの値取得を自動化に応用する考え方

別シートのセル値をループで取得できるようになると、単なる値の読み取りだけでなく、さまざまな業務自動化に応用できます。たとえば、入力シートから必要なデータだけを抽出して集計シートへ出力したり、管理表から対象データを探して帳票へ転記したり、複数シートのデータをまとめたりする処理です。実務では、こうした処理を手作業で行うと、コピー漏れや貼り付けミスが発生しやすくなります。VBAでループ処理を使えば、同じルールに沿って安定した処理を繰り返せます。ただし、自動化するほどコードの前提条件が重要になるため、シート構成や列の意味を整理しておく必要があります。小さな値取得の処理を丁寧に作ることが、壊れにくい自動化の第一歩です。

・入力シートから管理表へ転記する処理に応用できる

別シートの値取得は、次のような業務で使いやすいです。

  • 申請一覧から承認済みデータだけを取得する
  • 売上一覧から特定部門のデータだけを抽出する
  • 社員一覧から対象者だけを帳票へ転記する
  • 在庫表から発注対象の商品だけを出力する
  • 月別シートから集計シートへデータをまとめる

これらはすべて、「別シートの値を取得する」「条件を判定する」「必要な場所へ出力する」という流れで作れます。

つまり、今回の基本パターンを理解しておくと、かなり多くの実務マクロに応用できます。

・Excel関数とVBAを使い分ける視点も重要

別シートの値を取得するだけなら、Excel関数でも対応できる場合があります。

たとえば、単純に別シートのA2セルを参照するだけなら、次のような数式で十分です。

"=入力!A2"

また、条件に合う値を取得する場合は、VLOOKUP関数やXLOOKUP関数、FILTER関数などを使えるケースもあります。

一方で、次のような場合はVBAの方が向いています。

  • 複数行を条件に応じて転記したい
  • 出力先を毎回クリアして作り直したい
  • データ件数が多く、手作業での確認が大変
  • 複数のシートをまとめて処理したい
  • 処理ボタンを押すだけで完了させたい

Excel関数はシート上で結果を確認しやすいのがメリットです。
VBAは、一連の作業をまとめて自動化できるのがメリットです。

どちらが優れているというより、作業内容に応じて使い分けることが大切です。

・実務用マクロでは処理の入口と出口を明確にする

別シートの値取得を自動化に使う場合、次の3つを明確にすると設計しやすくなります。

  1. どのシートから取得するのか
  2. どの条件で取得するのか
  3. どのシートへ出力するのか

この3つが曖昧なままコードを書くと、後から処理内容が分かりにくくなります。

今回のコードでも、sourceSheetoutputSheetを分けているのはそのためです。
取得元と出力先の役割を分けることで、処理の流れが見えやすくなります。

また、条件値や列位置を定数化しておくと、仕様変更にも対応しやすくなります。
VBAで自動化する場合は、最初から完璧なコードを目指すよりも、後から直しやすい形にしておくことが重要です。

 

✅ まとめ:VBAで別シートのセル値をループ取得する基本を実務で活かそう

VBAで別シートのセルの値を取得する処理は、実務自動化の基本になる重要なテクニックです。
特にループ処理と組み合わせることで、一覧表のデータを1行ずつ読み取り、必要な情報だけを取得・出力できるようになります。

今回のポイントを整理すると、次の通りです。

  • 別シートの値を取得するときは、シート名を明示して指定する
  • ActiveSheetSelectに頼らず、Worksheet変数を使うと安全
  • 複数行の値を取得する場合は、最終行を取得してからループする
  • 取得元の行番号と出力先の行番号は分けて管理すると応用しやすい
  • 複数列を扱う場合は、意味のある変数名を使う
  • 列位置や条件値は定数化しておくと修正しやすい
  • シート存在チェックやデータ有無チェックを入れると実務で安定する
  • 大量データでは配列処理も選択肢になる
  • Excel関数で済む処理とVBAで自動化すべき処理を使い分けることが大切

別シートのセル値取得は、最初は小さな処理に見えるかもしれません。
しかし、実務ではこの処理を土台にして、データ抽出、転記、集計、帳票作成など多くの自動化へ発展させることができます。

まずは、シートを明示すること、最終行を取得すること、行番号を分けて管理することを意識してみてください。
この基本を押さえておくと、後から条件付き抽出や複数シート処理へ広げるときにも、壊れにくいVBAコードを作れるようになります。

    -VBAで自動化, VBA一覧, セル・値の取得と貼り付け, 取得