[作って]条件に一致したセルだけ操作するマクロ


【2025年8月】

AI(Copilot)を使えば、VBAを知らないシロウトでもマクロを作れる!って期待している方は多いでしょう。確かに便利なAIですが、はたして、そう上手くいくのでしょうか。実際に試してみましょう。

上図のデータで「A列が"田中"だったらB列の数値を2倍してC列に代入するマクロ」を作りたいです。なお、データの行数は分からないとします。まずは次のようなプロンプトで聞いてみましょう。

田中だったら2倍するマクロを作って

結果はこちら。

は?私「マクロを作って」って言いましたよね。う~ん、言い方が悪かったのかな。もう一度。

田中だったら2倍するVBAのコードを作って
Sub DoubleIfTanaka()
    Dim ws As Worksheet
    Dim i As Long
    Set ws = Worksheets("Sheet1")
    For i = 2 To 10 ' データ範囲A2:B10
        If ws.Cells(i, 1).Value = "田中" Then
            ws.Cells(i, 2).Value = ws.Cells(i, 2).Value * 2
        End If
    Next i
End Sub

よかった、伝わったようです。でもこれ、B列の数値を2倍して、B列に上書きしちゃいます。いや、[結果]って列があるんだから、そこに代入して欲しかったんだけどな。実行したらB列の数値が変わっちゃうとこだった。危ない。でも、そういうのも言わないと察してくれないんですね。

田中だったら数値を2倍して結果に入れるVBAのコードを作って

ざけんなよ!さっき作ってくれたじゃん。だったら、もっと丁寧に言いましょうか。

A列の値が"田中"の行だけ、B列の数値を2倍して、C列に代入するVBAのコードを作ってください。お願いします。
以下はご要望のVBAコードです。A列が「田中」の行だけ、B列の値を2倍してC列に代入します。

Sub TanakaDouble()
    Dim lastRow As Long
    Dim i As Long
    lastRow = Cells(Rows.Count, 1).End(xlUp).Row
    For i = 2 To lastRow ' ヘッダーが1行目の場合
        If Cells(i, 1).Value = "田中" Then
            Cells(i, 3).Value = Cells(i, 2).Value * 2
        End If
    Next i
End Sub

あざざます。完璧ですね。やっぱ、"親しき仲にも礼儀あり"みたいな。AIにも礼節を持って接しないといけませんね、人として。さて、コードの中で気になるのは「Cells(Rows.Count, 1).End(xlUp).Row」では?これの意味を聞いてみました。

「Cells(Rows.Count, 1).End(xlUp).Row」の意味を教えて
「Cells(Rows.Count, 1).End(xlUp).Row」は、
「A列(1列目)の一番下のセル(最終行)から上方向にデータがあるセルまで移動し、
そのセルの行番号を取得する」という意味です。

つまり、「A列で一番下までデータが入力されている行番号」を取得するVBAの書き方です。
データ範囲の最終行を調べるときによく使います。

なるほど、よく分かりました。

ポイント:
プロンプトの書き方によって、AIの回答は大きく異なります。「田中だったら数値を2倍して結果に入れる」では、どこの"田中"なのか、何の"数値"なのか、どこに"入れる"のかが定まりません。自分のやりたいことを詳細に記述するようにしましょう。

特定の行だけ書式を設定する

特定の行だけ、書式を設定してみましょう。条件は「E列が270以上」とします。該当する行全体の文字色を赤色にするマクロです。

E列の数値が「270以上」だったら、該当する行のA列からE列の文字色を、赤色にするVBAのコードを作って
E列の値が「270以上」の場合に、A列からE列の文字色を赤色にするVBAコードは以下の通りです。

Sub 赤文字にする()
    Dim i As Long
    For i = 2 To 10 ' データ範囲の行番号
        If Cells(i, 5).Value >= 270 Then
            Range(Cells(i, 1), Cells(i, 5)).Font.Color = RGB(255, 0, 0)
        End If
    Next i
End Sub

シンプルでいいですね。コードも無駄がなく完璧です。今回はデータの行数を10と特定してきました。もし、行数が不定だったら、先の「lastRow = Cells(Rows.Count, 1).End(xlUp).Row」と組み合わせればいいです。それくらいは、自分で考えましょう。私のセミナーでは毎回教えていますが「Range(Cells(i, 1), Cells(i, 5))」という書き方を、ご存じない方も多いかと。作ってくれたコードを、そのままコピーして満足するのではなく、分からないところを質問して、自分のVBA知識を高めることが重要ですね。

Range(Cells(i, 1), Cells(i, 5))は、どういう意味?
「Range(Cells(i, 1), Cells(i, 5))」は、VBAで「i行目のA列からE列まで
(つまりi行目のA~Eセル)」をまとめて指定する書き方です。

たとえば、iが2の場合は「A2:E2」を指します。
Cells(i, 1)は「i行目のA列」、Cells(i, 5)は「i行目のE列」です。
この2つをRangeでつなぐことで、その範囲全体(横一列)をまとめて操作できます。

分かりやすいですね。あと、どうやら「RGB(255, 0, 0)」というのは"赤色"の意味らしいです。これも確認します。

「RGB(255, 0, 0)」は、赤色の意味?
はい、「RGB(255, 0, 0)」は赤色を意味します。
RGBは「Red(赤), Green(緑), Blue(青)」の頭文字で、
それぞれの値(0~255)で色を指定します。
「255, 0, 0」は赤が最大、緑と青が0なので、純粋な赤色になります。

赤・緑・青の割合を、それぞれ0~255で指定するらしいです。では、別の色だったら、それぞれの数値はいくつなのでしょう?

別の色の、赤・緑・青割合は、どうやって調べるの?
Excelで使う「赤・緑・青(RGB)」の割合は、各色ごとに0~255の数値で指定します。
たとえば、以下のような割合です:

赤  RGB(255, 0, 0)
緑  RGB(0, 255, 0)
青  RGB(0, 0, 255)
黄色 RGB(255, 255, 0)
水色 RGB(0, 255, 255)
ピンクRGB(255, 0, 255)
黒  RGB(0, 0, 0)
白  RGB(255, 255, 255)
グレーRGB(128, 128, 128)
他の色も、Webで「RGB カラーコード」などで検索すると、色見本や割合を調べられます。
ExcelのVBAや条件付き書式で色を指定する場合、このRGB値を使います。

なるほど勉強になりました。ちなみに、色を表す「赤・緑・青の割合」のことを"RGB値"と呼びます。まぁ、正確には「赤・緑・青の割合」によって計算される数値ですけど。気になった方は「"RGB値"って何?」で調べてください。

ポイント:
コードの中で不明なろころがあったら、追加で質問しましょう。作ってくれるコードは、単なる成果物ではなく、あなたにとっての"教材"です。せっかくですから、AIによる個人授業で、VBAスキルを高めましょう。

特定の行だけコピーする

上図が、やりたいことの結果です。問題は、これをプロンプトとして、どう表現するかですね。

A列からD列の表で、C列の値が"A"の行だけ、セルF2から下方向にコピーするようなVBAのコードを作って

まずは、これでいってみましょう。

Sub CopyRowsWithAtoF2()
    Dim ws As Worksheet
    Dim srcLastRow As Long, destRow As Long
    Dim i As Long

    Set ws = Worksheets("Sheet3")
    srcLastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
    destRow = 2 ' F2から開始

    For i = 2 To srcLastRow
        If ws.Cells(i, 3).Value = "A" Then
            ws.Range(ws.Cells(i, 1), ws.Cells(i, 4)).Copy ws.Cells(destRow, 6)
            destRow = destRow + 1
        End If
    Next i
End Sub

さて、実務的に考えたとき、こうしたケースでは既存データの下に追記したいです。たとえば、前回の結果が4行目まであったら5行目から、10行目まであったら11行目から、みたいに。ややこしくなりますが、次のように聞いてみます。

A列からD列の表で、C列の値が"A"の行だけ、F列にコピーしたい。コピー先はすでに入力されている既存データの次行へ。たとえば、既存データが5行目まであったら6行目からコピーするようなVBAのコードを作って

ありゃ、なんと!まぁ、こういうときもありますよ。忙しいんでしょうね、きっと。もう一度聞いてみます。

Sub CopyRowsWithAtoF()
    Dim ws As Worksheet
    Dim lastRowSrc As Long, lastRowDest As Long, i As Long
    Set ws = ThisWorkbook.Sheets("Sheet3")
    
    ' コピー元の最終行(A列で判定)
    lastRowSrc = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
    
    ' コピー先の最終行(F列で判定)
    lastRowDest = ws.Cells(ws.Rows.Count, "F").End(xlUp).Row
    If lastRowDest < 2 Then lastRowDest = 1 ' ヘッダーのみの場合
    
    ' A列~D列のうち、C列が"A"の行だけF列以降にコピー
    For i = 2 To lastRowSrc
        If ws.Cells(i, "C").Value = "A" Then
            ws.Cells(lastRowDest + 1, "F").Value = ws.Cells(i, "A").Value
            ws.Cells(lastRowDest + 1, "G").Value = ws.Cells(i, "B").Value
            ws.Cells(lastRowDest + 1, "H").Value = ws.Cells(i, "C").Value
            ws.Cells(lastRowDest + 1, "I").Value = ws.Cells(i, "D").Value
            lastRowDest = lastRowDest + 1
        End If
    Next i
End Sub

上記は、AIの回答をそのままコピーしました。このコードを、そのままVBEのモジュールにコピーするとエラーになります。理由は「&lt;」です。HTMLにおいて「<」「>」「"」「&」などは、特別な意味を持つ記号です。これらの記号をHTML内に(単なる文字のつもりで)直接記述してしまうと、ブラウザは特殊な記号と認識してしまいます。そこで、これらの記号を"単なる文字"として扱う仕組みを実体参照と呼びます。実体参照では「<→&lt;」「>→&gt;」「"→&quot;」「&→&amp;」という文字で記述します。上記コードでは、本来「If lastRowDest < 2 Then lastRowDest = 1」としたいところが、実体参照の文字が表示されてしまったのでしょう。なので、もし上記のコードをVBEにコピーするときは、「&lt;」を「<」に書き換えてください。まぁ、HTMLあるあるです。

あと、細かいことが気になる人に向けて、ちょっと補足します。気にならない方はスルーしてください。今回のコードに限りませんが、AIが使う変数名は「lastRowSrc」のように、最初の単語の1文字目が小文字になっています。ちなみに「Src」は"Source"の略でしょう。「情報源・供給源」などの意味で、よくプログラミングでは「元データ」などとして使われます。また「lastRowDest」の「Dest」は、おそらく"Destination"の略でしょう。意味は「行き先・目的地」などを表します。今回のように"コピー先"などとして使われます。さて「lastRowSrc」は、"last"+"Row"+"Src"という3つの単語で構成されていますが、最初の単語「last」だけ1文字目が小文字です。このように、最初の単語だけ1文字目を小文字で記述するやり方を「キャメルケース」と呼びます。大文字のところが、ラクダのコブのように見えるからだそうです。変数名の記述ルールには、ほかにも「LastRowSrc」のように、すべての単語の1文字目を大文字にする「パスカルケース」や、「last_row_src」のように、単語間をアンダースコアでつないだ「スネークケース」などがあります。ヘビがくねっているように見えるからかな?一般的に、キャメルケースはJavaやJavaScriptなどでよく使われ、スネークケースはPythonなどで使われることが多いようです。

それでは、このコードの総評です。

・これはコピーじゃない

ws.Cells(lastRowDest + 1, "F").Value = ws.Cells(i, "A").Value

これは、セルのコピーではなく「値(Value)の代入」です。両者は意味が異なります。セルのコピーは、コピー元とコピー先が、まったく同じ状態になりますが、値の代入では書式が反映されません。また、セルに数式が入力されている場合、値の代入では、数式ではなく数式の計算結果が代入されます。コピーするときは、次のように書きます。

ws.Cells(i, "A").Copy ws.Cells(lastRowDest + 1, "F")

・複数セルの指定方法

ひとつつ前に提示されたコードで、複数セルの指定を次のようにしていました。

ws.Range(ws.Cells(i, 1), ws.Cells(i, 4))

だったら今回も次のようにできます。

ws.Range(ws.Cells(i, "A"), ws.Cells(i, "D")),Copy ws.Cells(lastRowDest + 1, "F")

これだけでマクロは、次のように短くなります。

Sub CopyRowsWithAtoF()
    Dim ws As Worksheet
    Dim lastRowSrc As Long, lastRowDest As Long, i As Long
    Set ws = ThisWorkbook.Sheets("Sheet3")
    
    ' コピー元の最終行(A列で判定)
    lastRowSrc = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
    
    ' コピー先の最終行(F列で判定)
    lastRowDest = ws.Cells(ws.Rows.Count, "F").End(xlUp).Row
    If lastRowDest < 2 Then lastRowDest = 1 ' ヘッダーのみの場合
    
    ' A列~D列のうち、C列が"A"の行だけF列以降にコピー
    For i = 2 To lastRowSrc
        If ws.Cells(i, "C").Value = "A" Then
            ws.Range(Cells(i, "A"), Cells(i, "D")).Copy ws.Cells(lastRowDest + 1, "F")
            lastRowDest = lastRowDest + 1
        End If
    Next i
End Sub

・一貫性に欠ける

ひとつ前のコードでシートを指定するとき、次のように記述されていました。

Set ws = Worksheets("Sheet3")

今回はこうです。

Set ws = ThisWorkbook.Sheets("Sheet3")

厳密に言うと、SheetsとWorksheetsは異なります。Sheetsには、ワークシートだけでなくグラフシートなども含まれますが、Worksheetsはワークシートだけです。その違いを重要視するのなら、毎回Worksheetsと書くべきです。ちなみに、よくセミナーを受講された方々にプチアンケートを取っていますが、グラフシートを使っている人はほとんどいませんし、そもそも存在を知らない人が多いです。ブック内にグラフシートがないのなら、両者は同じです。だったらスペルの短いSheetsが良いかなと、もっぱら私はSheetsを使っています。どっちでもいいんです。このへんは、作者の主義・主張です。どっちでもいいんですが、ブレるのはいただけません。マクロの中にSheetsとWorksheetsが混在すると、読もうとするビギナーは「区別しているのには、何か理由があるのかも」と、不要の疑問を持ちます。読者に疑問を抱かせたら、作者の負けです。

・Withステートメント

これは好みの問題です。AIはよく、オブジェクト変数を使います。それ自体は、まったく悪くないのですが、Withステートメントを使う方が、全体的にスッキリすると私は感じています。たとえば、次の二つのコードは、どちらも同じ動作です。

Set ws As Worksheet
Swt ws = Sheets("Sheet3")
ws.Range("A1").Value = 100
With Sheets("Sheet3")
    .Range("A1").Value = 100
End With

今回のコードを、オブジェクト変数ではなく、Withステートメントで書くと次のようになります。

Sub CopyRowsWithAtoF()
    Dim lastRowSrc As Long, lastRowDest As Long, i As Long
    With ThisWorkbook.Sheets("Sheet3")
        ' コピー元の最終行(A列で判定)
        lastRowSrc = .Cells(.Rows.Count, "A").End(xlUp).Row
        ' コピー先の最終行(F列で判定)
        lastRowDest = .Cells(.Rows.Count, "F").End(xlUp).Row
        If lastRowDest < 2 Then lastRowDest = 1 ' ヘッダーのみの場合
        ' A列~D列のうち、C列が"A"の行だけF列以降にコピー
        For i = 2 To lastRowSrc
            If .Cells(i, "C").Value = "A" Then
                .Range(Cells(i, "A"), Cells(i, "D")).Copy .Cells(lastRowDest + 1, "F")
                lastRowDest = lastRowDest + 1
            End If
        Next i
    End With
End Sub

Withステートメントは、ドット(.)で始まる書き方をしますので、慣れない方はイメージしにくいかもしれません。でも、少なくとも変数の宣言をしなくて済むので、コード全体がコンパクトになる効果があります。

まとめ

以上、VBAのコードを作ってもらうときのポイントをまとめます。

  • プロンプトの書き方によって、得られるコードは大きく異なります。望むコードを作ってもらうには、やりたいことを詳細に書かなければなりません。たとえば「売上を2倍して」ではなく「C列の数値を2倍して」などのように。これには、日本語の文章力だけでなく、日頃から"Excel用語"に慣れている必要があります。「これを持ってくる」「あっちから引っ張ってくる」みたいな、あなたにしか理解できない言葉は使わないように心がけてください。

  • コードは、"作ってもらって終わり"じゃありません。AIだって間違います。正常に動いているように見えて、もしかするとバグを含んでいるかもしれません。それに気づいて修正するのは、人間の仕事です。何が書いてあるか分からないけど、とり あえず動いたからいいや、では困ります。そのためには、あなた自身のVBAスキルを磨く必要があります。VBAの基礎を学習する必要があります。なので、作成されたコード内で不明なところがあったら、必ずAIに解説してもらいましょう

  • 現在のAIは、驚くほど高性能です。まるで、目の前の人と話しているような錯覚すら覚えます。とはいえ、AIはAIです。あくまでプログラムされた動作しかできません。たとえば、2種類のコードを作ってもらったとき、AIは1回目のコードを覚えていません。1回目と2回目では、異なる発想のコードが生成される可能性もあります。プログラミングでは、同じ結果を得るにしても、異なるアプローチが複数あります。どちらも根本的な間違いでなかったら、AIがどちらを選択するかは分かりませんし、同じプロンプトでも状況で変わるかもしれません。そうしたコードの一貫性を修正(統一)するのは、あなたの仕事です。

  • 繰り返しになりますが、AIも純粋に間違えます。原因は"ハルシネーション"とか"ポチョムキン理解"などと呼ばれる現象です。興味ある方は、AIに質問してみてください。間違いには、マクロが「エラーになって止まる」ものと、「エラーにはならないけど、結果が間違っている」ものがあります。どちらも困りますが、特に深刻なのは後者です。あなたの実務で間違った結果を出力し、それで企業全体が動いてしまうことを想像してください。あってはならないことです。そうした間違いに気づくためには、何よりも、あなた自身がExcelやVBAに精通していなければなりません。「AIが普及したから、もう勉強しないでいい」なんて甘いことを考えていたら、手痛いしっぺ返しをくらいますよ。