엑셀 매크로와 VBA 차이: 행 추가·필터 재실행까지 비교하기
매크로를 녹화했는데 새로 추가한 행만 모양이 다르다면, 먼저 저장된 범위를 읽어야 합니다. 이 글에서는 같은 가상 매출표에 고정 범위 서식과 마지막 행을 계산하는 서식을 적용하고, 겉모양 외에 합계와 필터 주소까지 비교합니다. 매크로는 실행할 작업이고 VBA는 그 작업을 표현하는 언어입니다. 매크로 기록기는 사용자의 작업 단계를 VBA 코드로 기록합니다. 둘을 서로 다른 자동화 제품으로 고를 필요는 없습니다.
6행에서 시작해 7행으로 늘리는 실험
practice-56.xlsx의 Source에는 날짜·부서·담당자·매출이 A:D에 있습니다. 금액은 순서대로 125000, 98000, 143000, 87000, 116000, 131000이며 모두 가상 입력입니다. 6행 합계는 700000입니다. Expected는 원래 6행의 서식 견본이고, 실행 로그가 아닙니다. Verification의 B열이 독립 기대값이며 C열과 D열은 매크로가 실제로 쓸 칸입니다. 배포 파일의 D7은 NOT_RUN입니다.
| 검사 위치 | 초기 기대값 | 무엇을 잡는가 |
|---|---|---|
| Verification!B2 | 6 | 데이터 행 누락 |
| B3 | 700000 | 값 변경 또는 범위 오류 |
| B4 | 31,78,120 | 머리글 전체의 배경색 |
| B5 | #,##0"원" | 매출 셀 전체의 표시 형식 |
| B6 | TRUE | 데이터 전체를 포함하는 필터 |
날짜는 비어 있지 않은 값인지 확인하지만 실제 달력 날짜인지 판정하지 않습니다. D열은 숫자 형식의 정수만 받습니다. 음수 정수까지 허용하므로 환불 정책을 구현한 코드라고 해석하지 마세요.
같은 입력에 두 매크로를 차례로 적용하기
매크로를 보관할 실습 사본은 매크로 사용 통합 문서인 .xlsm 형식으로 저장합니다. ZIP의 BAS를 해당 사본의 VBA 프로젝트로 가져오고, 아래 절차를 복사본에서 수행합니다. BAS 첫 줄의 Attribute는 가져오기용 메타데이터입니다. 코드 창에 전체를 붙여 넣는 대신 파일 가져오기를 사용합니다.
-
Source를 선택한 뒤
ResetSource,RecordedStyleExample,VerifyReport를 차례로 실행합니다. C2=6, C3=700000, C6=A1:D7과 D2:D7의 PASS를 직접 확인합니다. -
Source!A8:D8에
2026-08-30 / 온라인 / 지우 / 50000을 입력합니다. Verification!B2=7, B3=750000으로 기대값을 먼저 바꿉니다. ResetSource 후 고정 예제를 실행하고 검증하면 D8의 서식과 전체 필터 검사가 FAIL이어야 합니다. 합계만 맞는다고 성공으로 보지 않습니다. -
다시 ResetSource 후
RefactoredFormatReport와 VerifyReport를 실행합니다. 기대 필터는A1:D8, 행 수는 7, 합계는 750000입니다. 정상 실행 시 모든 검사 PASS가 예상되지만, 실제 Excel에서 확인한 뒤 결과로 기록해야 합니다.
ResetSource는 값이나 기대값을 원복하지 않습니다. 6행 실험으로 돌아가려면 새 사본을 열거나 추가한 A8:D8을 지우고 B2:B3도 되돌립니다. 단순히 Reset을 실행하고 합계가 복구됐다고 생각하면 다음 실험의 전제가 달라집니다.
완전한 참조 모듈
고정 예제의 Select/Selection은 녹화 코드의 특징을 비교하기 위해 남겨 두었습니다. 동적 예제는 A:D 전체에서 마지막 사용 행을 찾아 A열이 비었는데 D열만 있는 행도 놓치지 않습니다. Microsoft 문서는 Mac에서 Range.AutoFilter를 지원하지 않으며 Selection과 ListObject의 유사 메서드는 지원한다고 설명합니다. 그래서 필터 helper는 Mac에서 Source를 활성화하고 Selection을 사용합니다. 이 코드를 '선택 동작이 전혀 없는 코드'라고 부를 수는 없습니다.
Attribute VB_Name = "MacroVsVBA"
Option Explicit
Public Sub RecordedStyleExample()
Dim ws As Worksheet
On Error GoTo Fail
InvalidateVerification
Set ws = ThisWorkbook.Worksheets("Source")
ThisWorkbook.Activate
ws.Activate
If ws.AutoFilterMode Then ws.AutoFilterMode = False
' Deliberately fixed: compare this with the dynamic procedure.
Range("A1:D7").Select
Selection.Borders.LineStyle = xlContinuous
Range("A1:D1").Select
With Selection
.Interior.Color = RGB(31, 78, 120)
.Font.Color = RGB(255, 255, 255)
.Font.Bold = True
End With
Range("D2:D7").Select
Selection.NumberFormat = AmountFormat()
Range("A1:D7").Select
Selection.AutoFilter
ws.Columns("A:D").AutoFit
Exit Sub
Fail:
ReportFailure "Recorded format", Err.Description
End Sub
Public Sub RefactoredFormatReport()
Dim ws As Worksheet
Dim lastRow As Long
Dim previousUpdating As Boolean
Dim detail As String
previousUpdating = Application.ScreenUpdating
On Error GoTo Fail
InvalidateVerification
Set ws = ThisWorkbook.Worksheets("Source")
lastRow = ValidatedDataLastRow(ws)
Application.ScreenUpdating = False
ws.Range("A1:D" & lastRow).Borders.LineStyle = xlContinuous
With ws.Range("A1:D1")
.Interior.Color = RGB(31, 78, 120)
.Font.Color = RGB(255, 255, 255)
.Font.Bold = True
End With
ws.Range("D2:D" & lastRow).NumberFormat = AmountFormat()
EnableReportFilter ws, lastRow
ws.Columns("A:D").AutoFit
Application.ScreenUpdating = previousUpdating
Exit Sub
Fail:
detail = Err.Description
On Error Resume Next
Application.ScreenUpdating = previousUpdating
On Error GoTo 0
ReportFailure "Dynamic format", detail
End Sub
Public Sub ResetSource()
Dim ws As Worksheet
Dim lastRow As Long
On Error GoTo Fail
InvalidateVerification
Set ws = ThisWorkbook.Worksheets("Source")
lastRow = LastOccupiedRow(ws)
If ws.AutoFilterMode Then ws.AutoFilterMode = False
ws.Range("A1:D" & lastRow).ClearFormats
ws.Columns("A:D").ColumnWidth = 14
' No Select: this also works while another sheet is active.
Exit Sub
Fail:
ReportFailure "Reset", Err.Description
End Sub
Public Sub VerifyReport()
Dim ws As Worksheet, checkWs As Worksheet
Dim lastRow As Long, actualRows As Long
Dim actualTotal As Double, expectedRows As Variant, expectedTotal As Variant
Dim expectedColor As String, expectedFormat As String
Dim headerOK As Boolean, formatOK As Boolean, filterOK As Boolean
Dim filterAddress As String, overallOK As Boolean
Dim cell As Range
On Error GoTo Fail
InvalidateVerification
Set checkWs = ThisWorkbook.Worksheets("Verification")
Set ws = ThisWorkbook.Worksheets("Source")
checkWs.Range("D7").Value2 = "ERROR"
lastRow = ValidatedDataLastRow(ws)
actualRows = lastRow - 1
actualTotal = WorksheetFunction.Sum(ws.Range("D2:D" & lastRow))
expectedRows = checkWs.Range("B2").Value2
expectedTotal = checkWs.Range("B3").Value2
If Not NativeNumber(expectedRows) Then Err.Raise vbObjectError + 5601, , "B2 must be a numeric row count."
If expectedRows < 1 Or expectedRows > ws.Rows.Count - 1 Or expectedRows <> Fix(expectedRows) Then
Err.Raise vbObjectError + 5602, , "B2 is outside the data-row range."
End If
If Not NativeNumber(expectedTotal) Then Err.Raise vbObjectError + 5603, , "B3 must be a numeric total."
If expectedTotal <> Fix(expectedTotal) Then Err.Raise vbObjectError + 5604, , "This example uses integer KRW amounts."
expectedColor = CStr(checkWs.Range("B4").Value2)
expectedFormat = AmountFormat()
If VarType(checkWs.Range("B6").Value2) <> vbBoolean Then
Err.Raise vbObjectError + 5605, , "Keep B6 as the Boolean TRUE for this exercise."
End If
If Not CBool(checkWs.Range("B6").Value2) Then
Err.Raise vbObjectError + 5606, , "This exercise requires the full-range filter."
End If
headerOK = True
For Each cell In ws.Range("A1:D1")
If RGBLabel(CLng(cell.Interior.Color)) <> expectedColor Then headerOK = False
Next cell
formatOK = True
For Each cell In ws.Range("D2:D" & lastRow)
If CStr(cell.NumberFormat) <> expectedFormat Then formatOK = False
Next cell
filterAddress = "(none)"
If ws.AutoFilterMode Then filterAddress = ws.AutoFilter.Range.Address(False, False)
filterOK = (filterAddress = ws.Range("A1:D" & lastRow).Address(False, False))
checkWs.Range("C2").Value2 = actualRows
checkWs.Range("C3").Value2 = actualTotal
checkWs.Range("C4").Value2 = IIf(headerOK, expectedColor, "MIXED_OR_WRONG")
checkWs.Range("C5").Value2 = IIf(formatOK, expectedFormat, "MIXED_OR_WRONG")
checkWs.Range("C6").Value2 = filterAddress
checkWs.Range("D2").Value2 = PassFail(actualRows = CLng(expectedRows))
checkWs.Range("D3").Value2 = PassFail(actualTotal = CDbl(expectedTotal))
checkWs.Range("D4").Value2 = PassFail(headerOK)
checkWs.Range("D5").Value2 = PassFail(formatOK)
checkWs.Range("D6").Value2 = PassFail(filterOK)
overallOK = WorksheetFunction.CountIf(checkWs.Range("D2:D6"), "PASS") = 5
checkWs.Range("D7").Value2 = PassFail(overallOK)
MsgBox "Verification: " & checkWs.Range("D7").Value2, IIf(overallOK, vbInformation, vbExclamation)
Exit Sub
Fail:
ReportFailure "Verification", Err.Description
End Sub
Private Sub EnableReportFilter(ByVal ws As Worksheet, ByVal lastRow As Long)
If ws.AutoFilterMode Then ws.AutoFilterMode = False
If InStr(1, Application.OperatingSystem, "Mac", vbTextCompare) > 0 Then
' Microsoft documents Selection.AutoFilter as supported on Mac.
ThisWorkbook.Activate
ws.Activate
ws.Range("A1:D" & lastRow).Select
Selection.AutoFilter
Else
ws.Range("A1:D" & lastRow).AutoFilter
End If
End Sub
Private Function LastOccupiedRow(ByVal ws As Worksheet) As Long
Dim lastCell As Range
Set lastCell = ws.Range("A:D").Find(What:="*", After:=ws.Range("A1"), _
LookIn:=xlFormulas, LookAt:=xlPart, SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, MatchCase:=False, SearchFormat:=False)
If lastCell Is Nothing Then
LastOccupiedRow = 1
Else
LastOccupiedRow = lastCell.Row
End If
End Function
Private Function ValidatedDataLastRow(ByVal ws As Worksheet) As Long
Dim lastRow As Long, r As Long, value As Variant
lastRow = LastOccupiedRow(ws)
If lastRow < 2 Then Err.Raise vbObjectError + 5610, , "Source has no data rows."
For r = 2 To lastRow
value = ws.Cells(r, "A").Value2
If IsError(value) Then Err.Raise vbObjectError + 5611, , "Date cell error in row " & r
If Len(Trim$(CStr(value))) = 0 Then Err.Raise vbObjectError + 5612, , "Missing date in row " & r
value = ws.Cells(r, "D").Value2
If Not NativeNumber(value) Then Err.Raise vbObjectError + 5613, , "Amount must be numeric, not text, in row " & r
If value <> Fix(value) Then Err.Raise vbObjectError + 5614, , "Use integer KRW in row " & r
Next r
ValidatedDataLastRow = lastRow
End Function
Private Function NativeNumber(ByVal value As Variant) As Boolean
Select Case VarType(value)
Case vbByte, vbInteger, vbLong, vbSingle, vbDouble, vbCurrency, vbDecimal
NativeNumber = True
Case Else
NativeNumber = False
End Select
End Function
Private Function AmountFormat() As String
AmountFormat = CStr(ThisWorkbook.Worksheets("Verification").Range("B5").Value2)
If Len(AmountFormat) = 0 Then Err.Raise vbObjectError + 5615, , "B5 must contain the amount number format."
End Function
Private Sub InvalidateVerification()
With ThisWorkbook.Worksheets("Verification")
.Range("C2:D7").ClearContents
.Range("D7").Value2 = "NOT_RUN"
End With
End Sub
Private Sub ReportFailure(ByVal stageName As String, ByVal detail As String)
On Error Resume Next
ThisWorkbook.Worksheets("Verification").Range("D7").Value2 = "ERROR"
On Error GoTo 0
MsgBox stageName & ": " & detail, vbExclamation
End Sub
Private Function PassFail(ByVal condition As Boolean) As String
PassFail = IIf(condition, "PASS", "FAIL")
End Function
Private Function RGBLabel(ByVal colorValue As Long) As String
RGBLabel = CStr(colorValue Mod 256) & "," & _
CStr((colorValue \ 256) Mod 256) & "," & _
CStr((colorValue \ 65536) Mod 256)
End Function
실패를 만들고 복구하는 순서
A8은 지운 채 D8=50000만 남기면 검증은 날짜 누락 오류여야 합니다. 숫자 125000 대신 문자 '125000을 D2에 넣어도 숫자로 자동 변환하지 않고 거부해야 합니다. 잘못된 셀을 고친 뒤 동적 서식과 VerifyReport를 다시 실행합니다. ERROR 뒤에는 이전 PASS나 이전 합계를 근거로 보고서를 쓰지 않습니다.
예상 결과와 실제 결과를 같은 칸에 넣지 않는 것이 이 실험의 핵심입니다. Verification!C열에 기대값을 손으로 복사하면 검증이 아니라 결과 꾸미기가 됩니다. 오류 경로는 표시를 ERROR로 바꾸도록 작성됐지만, 시트가 없어지거나 보호돼 쓰지 못하면 그 표시도 남기지 못할 수 있습니다. 메시지를 먼저 읽고 새 사본에서 복구하세요.
확인한 범위와 남은 확인
첨부 Python 검산은 6행·7행의 합계, 잘못된 값의 입력 계약, 고정/확장 범위의 차이를 독립적으로 확인합니다. XLSX 구조와 VBA 소스의 참조도 검사했습니다. Microsoft Excel에서 VBA를 컴파일하거나 실행하지 않았습니다. 색·테두리·필터 UI와 운영체제별 실행 결과는 위 절차로 직접 확인해야 합니다. 원본 파일 보호, 자동 백업, 대량 자료의 속도 측정은 포함하지 않습니다.
입력과 결과 칸을 찾는 기존 그림
그림은 실습 위치를 찾는 보조 자료입니다. 실제 실행 결과는 위 절차로 만든 사본의 값과 상태를 대조합니다.



공식 자료
Automate tasks with the Macro Recorder | Microsoft Support
Save a macro | Microsoft Support
Range.AutoFilter method (Excel)
출처 원문 수집일: S1 2026-09-24; S2 2026-09-24; S3 2026-09-24.
이어서 연습할 글
녹화 단계부터 다시 확인하려면 매크로 기록기로 영업 필터 범위 검산하기를, 실행할 코드를 단추에 연결하려면 집계 결과와 오류를 확인하는 매크로 버튼 예제를 이어서 보세요.