녹화한 매크로 수정하기: VBA 기초 5가지와 완료 행 추출
녹화한 코드에서 범위 주소만 바꿔 가며 완료 행을 복사하다 보면, 완료 건수가 0일 때나 잘못된 금액이 섞였을 때 결과가 애매해집니다. 이 실습은 상태가 완료인 행을 같은 파일의 Result로 옮기며 변수·조건·반복·범위 지정·오류 복구를 한 작업 안에서 읽습니다. 실제 업무에서 쓴 경험을 주장하는 사례가 아니라 재현용 가상 자료입니다.
완료 2행과 결과 영역의 경계
practice-60.xlsx의 Data!A1:E5는 상태, 담당 기호, 금액, 기준일, 메모 순서입니다. 조건은 Check!B2의 완료입니다.
| 상태 | 담당 기호 | 금액 | 가상 기준일 | 메모 |
|---|---|---|---|---|
| 완료 | 담당-A | 120000 | 2026-09-01 | 확인 |
| 대기 | 담당-B | 95000 | 2026-09-01 | 검토 |
| 완료 | 담당-C | 180000 | 2026-09-02 | 확인 |
| 보류 | 담당-D | 70000 | 2026-09-02 | 자료 대기 |
독립 기대값은 담당-A,담당-C 순서의 2행, 합계 300000입니다. Result!A2:E1001은 이 매크로의 예약 출력 영역입니다. 재실행 때 비워지므로 다른 자료를 넣으면 안 됩니다. G열의 연습 메모는 이 영역 밖이며 보존 대상입니다. 날짜는 값으로 복사할 뿐 유효한 날짜인지 검사하지 않습니다.
다섯 가지를 코드의 실제 역할로 연결하기
Option Explicit와 Dim은 어느 변수가 시트인지, 행인지, 임시 출력 배열인지 드러냅니다. If는 입력을 거부할 조건과 선택할 조건을 나눕니다. For Each는 배열이나 컬렉션의 각 요소에 대해 문장 묶음을 반복합니다. 이 코드에서는 Data의 행을 검사합니다. With와 ThisWorkbook은 다른 활성 파일의 셀에 쓰는 실수를 줄이도록 대상을 명시합니다. 마지막 On Error 경로는 이전 결과를 지우고 화면 갱신·이벤트 값을 복구하도록 구성했습니다.
Range.Value2는 셀 값을 읽고 쓰는 Variant 속성입니다. 여러 행을 고른 다음 출력 배열에 담아 Result로 쓰지만, 단지 배열을 쓴다는 이유로 처리 속도를 보장하지 않습니다.
전체 모듈을 넣고 2행·0행·3행을 비교하기
매크로를 저장할 연습 사본은 .xlsm 형식을 사용합니다. CompletedRows.bas를 사본의 VBA 프로젝트로 가져옵니다. 첫 Attribute 줄은 가져오기용이며, VBA 편집기의 파일 가져오기를 사용합니다.
-
새 사본에서 Check!B2와 B7:B9를 선택해 조건과 기대값을 확인하고
CopyCompletedRows를 실행합니다. Result!A2:E3에 담당-A,C가 들어가는지, Check!C7=2·C8=300000인지 확인합니다. 결과에서 담당 기호를 직접 읽어 C9에담당-A,담당-C로 입력합니다. -
별도 새 사본에서 Data!A2와 A4를 대기로 바꿉니다. 기대값 B7=0, B8=0, B9=
(없음)을 입력하고 실행합니다. 예약 결과 영역은 비어 있고 G열 메모는 남아야 합니다. C9에도 직접(없음)을 적어 비교합니다. -
다시 원본 사본에서 A3만 완료로 바꿉니다. 기대값은 3행, 395000, 담당-A,담당-B,담당-C입니다. 결과 순서와 합계가 모두 맞는지 확인합니다. 각 실험은 다른 사본에서 시작해 이전 변경을 섞지 않습니다.
Attribute VB_Name = "CompletedRows"
Option Explicit
Public Sub CopyCompletedRows()
Const LAST_ALLOWED As Long = 1001
Dim wsData As Worksheet, wsResult As Worksheet, wsCheck As Worksheet
Dim rowRange As Range, picked As Collection, item As Variant
Dim lastRow As Long, candidate As Long, colNo As Long, outRow As Long
Dim criterion As Variant, state As Variant, amount As Variant
Dim values() As Variant
Dim savedScreen As Boolean, savedEvents As Boolean
Dim resultReady As Boolean, checkReady As Boolean, problem As String
savedScreen = Application.ScreenUpdating
savedEvents = Application.EnableEvents
On Error GoTo Failed
Set wsCheck = ThisWorkbook.Worksheets("Check")
If wsCheck.ProtectContents Then
Err.Raise vbObjectError + 601, , "Use an unprotected practice Check sheet."
End If
checkReady = True
Set wsResult = ThisWorkbook.Worksheets("Result")
If wsResult.ProtectContents Then
Err.Raise vbObjectError + 602, , "Use an unprotected practice Result sheet."
End If
resultReady = True
Application.ScreenUpdating = False
Application.EnableEvents = False
wsCheck.Range("B3").Value2 = "RUNNING"
wsCheck.Range("B4").ClearContents
wsCheck.Range("C9").ClearContents
wsResult.Range("A2:E" & LAST_ALLOWED).ClearContents
Set wsData = ThisWorkbook.Worksheets("Data")
wsResult.Range("A1:E1").Value2 = wsData.Range("A1:E1").Value2
criterion = wsCheck.Range("B2").Value2
If VarType(criterion) <> vbString Then
Err.Raise vbObjectError + 603, , "Check!B2 must contain a text condition."
End If
If Len(criterion) = 0 Or criterion <> Trim$(criterion) Then
Err.Raise vbObjectError + 604, , "Check!B2 must be nonempty without outer spaces."
End If
lastRow = 1
With wsData
For colNo = 1 To 5
candidate = .Cells(.Rows.Count, colNo).End(xlUp).Row
If candidate > lastRow Then lastRow = candidate
Next colNo
End With
If lastRow > LAST_ALLOWED Then
Err.Raise vbObjectError + 605, , "Practice input is limited to rows 2 through 1001."
End If
If lastRow < 2 Then GoTo Complete
Set picked = New Collection
For Each rowRange In wsData.Range("A2:E" & lastRow).Rows
With rowRange
If Application.WorksheetFunction.CountA(rowRange) > 0 Then
For colNo = 1 To 5
If IsError(.Cells(1, colNo).Value2) Then
Err.Raise vbObjectError + 606, , "Cell error at row " & .Row
End If
Next colNo
state = .Cells(1, 1).Value2
If VarType(state) <> vbString Then
Err.Raise vbObjectError + 607, , "Text status required at row " & .Row
End If
If Len(state) = 0 Or state <> Trim$(state) Then
Err.Raise vbObjectError + 608, , "Empty status or outer spaces at row " & .Row
End If
If Len(Trim$(CStr(.Cells(1, 2).Value2))) = 0 Then
Err.Raise vbObjectError + 609, , "Missing owner label at row " & .Row
End If
amount = .Cells(1, 3).Value2
Select Case VarType(amount)
Case vbByte, vbInteger, vbLong, vbSingle, vbDouble, vbCurrency, vbDecimal
Case Else
Err.Raise vbObjectError + 610, , "Numeric amount required at row " & .Row
End Select
If amount < 0 Or amount > 1000000000# Or amount <> Fix(amount) Then
Err.Raise vbObjectError + 611, , "Invalid whole amount at row " & .Row
End If
If StrComp(state, criterion, vbBinaryCompare) = 0 Then picked.Add .Row
End If
End With
Next rowRange
If picked.Count = 0 Then GoTo Complete
ReDim values(1 To picked.Count, 1 To 5)
For Each item In picked
outRow = outRow + 1
For colNo = 1 To 5
values(outRow, colNo) = wsData.Cells(CLng(item), colNo).Value2
Next colNo
Next item
wsResult.Range("A2").Resize(picked.Count, 5).Value2 = values
Complete:
wsCheck.Range("B3").Value2 = "OK"
wsCheck.Range("B4").Value = Now
wsCheck.Calculate
CleanExit:
Application.EnableEvents = savedEvents
Application.ScreenUpdating = savedScreen
Exit Sub
Failed:
problem = Err.Description
On Error Resume Next
If resultReady Then wsResult.Range("A2:E" & LAST_ALLOWED).ClearContents
If checkReady Then
wsCheck.Range("B3").Value2 = "ERROR"
wsCheck.Range("B4").ClearContents
wsCheck.Range("C9").ClearContents
wsCheck.Calculate
End If
Application.EnableEvents = savedEvents
Application.ScreenUpdating = savedScreen
On Error GoTo 0
MsgBox "Copy failed: " & problem, vbExclamation
End Sub
선택되지 않을 행도 검증해야 하는 이유
이 모듈은 비어 있지 않은 모든 입력 행을 먼저 검증합니다. 따라서 대기 행의 금액이 문자여도 전체 처리가 ERROR가 됩니다. 잘못된 자료가 이번 조건에서 우연히 제외됐다고 정상 원장으로 인정하지 않기 위한 연습 계약입니다. 상태는 문자열이며 앞뒤 공백을 허용하지 않고, 담당 기호가 비거나 셀 오류가 있어도 거부합니다. 금액은 숫자 형식의 0~1000000000 정수입니다.
Data!A2에 완료 처럼 끝 공백을 넣거나 C2에 문자 '120000을 입력해 실패를 확인합니다. 출력 영역이 비고 Check!B3가 ERROR로 바뀌는 것이 기대 동작입니다. 값을 고쳐 재실행한 뒤 2행·300000과 대조하세요. 매크로는 C9의 수동 관찰을 매번 지우므로 이전 목록을 그대로 재사용하지 않습니다.
Data 값과 필터 상태, Result의 G열은 변경 대상이 아닙니다. 반면 오류가 났다고 이전 A:E 결과를 복구하는 기능은 없습니다. 오래된 결과를 남기지 않는 방식이며 백업·트랜잭션 롤백과 다릅니다. 쓰기 불가능한 시트에서는 지우기나 ERROR 표시조차 실패할 수 있으므로 경고 메시지를 무시하지 않습니다.
독립 검산과 한계
첨부 Python 검산은 기본·0건·3건 결과와 선택 밖의 오류 행 거부를 확인합니다. XLSX의 예약 결과가 처음에는 비어 있고 G열 메모가 따로 있다는 점도 검사했습니다. Excel/VBA를 실행하지 않았으므로 실제 복사, 설정 복구, 컴파일 결과는 확인되지 않았습니다. 실습 상한은 데이터 1000행이고 숨김 행도 검사합니다. 이 코드는 여러 파일 병합이나 취소 가능한 편집기를 대신하지 않습니다.
입력과 결과 칸을 찾는 기존 그림
그림은 실습 위치를 찾는 보조 자료입니다. 실제 실행 결과는 위 절차로 만든 사본의 값과 상태를 대조합니다.



공식 자료
Save a macro | Microsoft Support
출처 원문 수집일: S1 2026-09-24; S2 2026-09-24; S3 2026-09-24.
이어서 연습할 글
반복 범위를 더 크게 확인하려면 For 루프로 1,000행 분류하기를, 만든 매크로를 단추에 연결하려면 집계 결과를 확인하는 매크로 버튼 예제를 이어서 보세요.