- 최초 작성일: 2000-07-06
- 최종 수정일: 2026-09-30
- 조회수: 11 회
- 작성자: 권현욱 (엑셀러)
- 강의 제목: 동일내역 전표지우기
들어가기 전에
오래 전 엑셀 파일로 진행하던 강의를 웹 글로 복원한 것이라, "버튼을 눌러보세요"처럼 엑셀에서 직접 조작하라는 표현이 남아 있을 수 있습니다. 결과는 본문의 그림이나 표로 확인하실 수 있으며, 현재와 맞지 않는 내용은 보완하되 전반적인 스타일은 당시의 갬성(?)을 유지했습니다.
제가 회사 업무를 보다가 업무량이 많다보니 도저히 도저히 손으로는 못할 지경입니다.
제발 도와 주십시요.
요건은 다음과 같습니다.
업체가 여러개 있는데 같은 업체 같은 금액이 여러개다 보니 엑셀에서 찾지를 못합니다.
거래처에서는 여러 회사의 제품을 저의 회사에 공급합니다.
어떤 일을 하든 일의 순서를 잘 정립해 두고 시작을 해야 뒤에 가서 헤매지 않을 것입니다. 특히 프로그래밍을 함에 있어서는 더욱 그러합니다. 코드가 짧은 경우라 하더라도 순서도를 한번쯤 그려본 다음에 코딩에 들어가 는 것이 좋을 것입니다.
동일내역 전표지우기
핵심 요약: 두 장부의 동일 내역 지우기
순서도를 먼저 그려 네 단계로 나눈 뒤, 기준 시트를 바꿔 가며 같은 로직을 두 번 실행합니다.
- 1단계: 두 시트의 기준 셀에 Dealer, Company 이름을 지정합니다.
- 2단계: 기준 시트의 중복 레코드를 찾으면 상대 시트의 같은 레코드를 삭제합니다.
- 3단계: 기준 시트를 바꾸어 같은 작업을 한 번 더 실행합니다.
질문
제가 회사 업무를 보다가 업무량이 많다보니 도저히 도저히 손으로는 못할 지경입니다.
제발 도와 주십시요.
요건은 다음과 같습니다.
업체가 여러개 있는데 같은 업체 같은 금액이 여러개다 보니 엑셀에서 찾지를 못합니다.
거래처에서는 여러 회사의 제품을 저의 회사에 공급합니다.
예를 들어,
거래처 장부
| 업체명 | 출고금액 | 환급금액 |
|---|---|---|
| 오뚜기 | 1000 | 10 |
| 엘지 | 500 | 20 |
| 오뚜기 | 1000 | 10 |
이라 하면,
저희 회사 장부에는
| 업체명 | 구매금액 | 환급금액 |
|---|---|---|
| 엘지 | 500 | 20 |
| 오뚜기 | 1000 | 10 |
| 태평양 | 600 | 60 |
| 엘지 | 500 | 20 |
입니다. 두개의 장부에서 업체별 금액별 환급금액별로 맞는 것을 서로 지워줘 가면서 최종적으로 대사가
안된 업체의 구입금액 환급금액을 남겨야 하는데… 같은 업체, 같은 금액이 여러 개 있으면 엑셀이 정확
하게 나타나지 않는다는 문제가 있습니다. 위에서 제가 원하는 답은
거래처 장부
| 업체명 | 출고금액 | 환급금액 |
|---|---|---|
| 오뚜기 | 1000 | 10 |
저희 회사장부
| 업체명 | 구매금액 | 환급금액 |
|---|---|---|
| 태평양 | 600 | 60 |
| 엘지 | 500 | 20 |
날짜는 출고날짜와 입고날짜가 거의 맞는 경우가 없어서 날짜로 맞추는 경우는 불가능하고요.
방법이 없겠습니까?
답변
위에서 질문하신 분의 질문 요점을 정확히 파악했는지 잘 모르겠지만 일단 위의 내용만 가지고서 유추한 결과, 아래와 같은 순서로 하면 될 것이라고 생각이 드는군요.
- (1) "거래처장부"에서 같은 레코드가 있으면 하나만 남기고 삭제 처리
- (2) 이 레코드를 "회사장부"와 비교해서 역시 같은 레코드가 있으면 "회사장부" 내의 모든 같은 레코드 삭제
- (3) "회사장부"에 있는 레코드들을 확인해서 중복되는 레코드가 있으면 하나만 남기고 삭제 처리
- (4) 이 레코드를 "거래처장부"와 비교해서 같은 레코드가 있으면 "거래처장부" 내의 모든 같은 레코드 삭제
이상과 같은 네 단계로 나누어 작업을 진행하면 원하는 결과를 얻으실 수 있을 것 같군요. 만약 로직이 약간 다르다 할 지라도 그건 큰 문제가 아니겠지요? 바뀐 로직에 해당하는 부분만 손질해 주면 될테니까 말이지요.
이름 정의하기
먼저, 어디서부터(즉 어느 셀에서부서) 작업을 시작할 지 지정을 하기 위해 "거래처장부" 시트의 A3 셀에는 "Dealer", "회사장부" 시트의 A3 셀에는 "Company"라는 이름을 각각 지정해 주었습니다. 이름을 어떻게 지정하느냐고요?(이거 큰일인걸~~ ^^). 원하는 셀(또는 범위)을 선택한 후 "삽입-이름-정의" 메뉴를 선택하고 주시든가 아니면, 범위를 지정한 다음 "수식입력줄" 맨 왼쪽에 있는 "이름상자"에 그냥 이름 을 입력하시면 되지요.
이처럼 어떤 기준이 되는 셀 또는 영역에 이름을 부여하고 프로그래밍에서 활용하는 것은 아주 좋은 방법입 니다. 가급적 이 방법을 사용하실 것을 적극 권장합니다.
코드 살펴보기
이제 코드를 살펴 볼까요? 오늘 코드는 이벤트 핸들러 프로시저가 아닌 일반 프로시저이므로 일반 모듈(General VBA Module)에다 입력을 하시면 되겠습니다. 코딩을 한 다음 최적화(Optimizing)를 하지 않아서 좀 눈에 거슬리는 부분도 보이는 군요. 시간상 그런 거니까 양해하시고 그런 부분은 직접 수정해 보시기를…
Sub Summary()
Dim wsDealer As Worksheet
Dim wsCompany As Worksheet
Dim lngDealer As Long
Dim lngCompany As Long
'//"Dealer"와 "Company"라는 이름이 지정된 셀의 시트와 행 번호를 각각 구해 둡니다.
Set wsDealer = Range("Dealer").Worksheet
Set wsCompany = Range("Company").Worksheet
lngDealer = Range("Dealer").Row
lngCompany = Range("Company").Row
Call RemoveDuplicates(wsDealer, lngDealer, wsCompany, lngCompany)
'//순서 (1), (2): "거래처장부"의 중복 레코드를 정리하면서 "회사장부"의 같은 레코드를 삭제합니다.
Call RemoveDuplicates(wsCompany, lngCompany, wsDealer, lngDealer)
'//순서 (3), (4): 이번에는 기준 시트를 바꾸어 "회사장부"의 중복 레코드를 정리하면서
'//"거래처장부"의 같은 레코드를 삭제합니다. 두 단계는 기준 시트만 다를 뿐 같은 로직입니다.
End Sub
Private Sub RemoveDuplicates(wsBase As Worksheet, lngBase As Long, _
wsOther As Worksheet, lngOther As Long)
Dim lngLast As Long
Dim lngRow As Long
Dim lngRow1 As Long
Dim lngRow2 As Long
Dim blnDupe As Boolean
lngLast = wsBase.Cells(wsBase.Rows.Count, 1).End(xlUp).Row
'//기준 시트에서 업체명이 입력된 마지막 행을 구합니다.
For lngRow = lngLast To lngBase + 1 Step -1
'//행을 삭제하면 아래 행들이 위로 밀려 올라오므로 맨 아래에서부터 위로 검사합니다.
blnDupe = False
For lngRow1 = lngBase To lngRow - 1
If SameRecord(wsBase, lngRow, wsBase, lngRow1) Then
blnDupe = True
Exit For
End If
Next lngRow1
'//현재 레코드보다 위에 있는 레코드 중에 업체명, 금액, 환급금액이 모두 같은 것이 있는지 검사합니다.
If blnDupe Then
For lngRow2 = wsOther.Cells(wsOther.Rows.Count, 1).End(xlUp).Row To lngOther Step -1
If SameRecord(wsBase, lngRow, wsOther, lngRow2) Then
wsOther.Rows(lngRow2).Delete
End If
Next lngRow2
'//상대 시트에서 같은 값을 가진 레코드가 있으면 그 행 전체를 삭제합니다.
wsBase.Rows(lngRow).Delete
'//기준 시트의 중복된 레코드도 삭제합니다.
End If
Next lngRow
End Sub
Private Function SameRecord(ws1 As Worksheet, lngRow1 As Long, _
ws2 As Worksheet, lngRow2 As Long) As Boolean
Dim intCol As Integer
SameRecord = True
For intCol = 1 To 3
If ws1.Cells(lngRow1, intCol).Value <> ws2.Cells(lngRow2, intCol).Value Then
SameRecord = False
Exit For
End If
Next intCol
'//업체명, 금액, 환급금액 세 열이 모두 같은 경우에만 같은 레코드로 판단합니다.
End Function
마무리
오늘 설명드린 코드는 지금까지 중에서 가장 길고 논리적으로 약간 복잡하게 느껴지는군요. "시작이 반"이라는 말이 있습니다.
프로그래밍을 함에 있어 "좋은" 시작(즉 순서를 미리 그려보는 것!)은 "반"이 아니라 90% 이상입니다. 물론 "90%라는 구체적인 근거를 대라!!!"고 한다면 근거를 댈 수는 없지만 그만큼 구상을 미리 해 보는 것, 즉 "문제의 구체화 작업"은 중요한 것입니다. 이러한 생각의 구체화, 문제의 구체화 작업없이 마구잡이로 바로 코딩에 들어가면 곧 머리가 혼란스러워 집니다.
다른 것은 다 잊어버려도 이것 한 가지는 필히 기억하세요! "구체화 된(또는 잘 정리된) 문제는 해결된 것이나 다름없다!!!"는 사실…
오늘은 여기까지…
정리 — 전표 대사 핵심
| 구분 | 사용한 코드 | 역할 |
|---|---|---|
| 기준 셀 | Range("Dealer"), Range("Company") | 작업 시작 위치 |
| 중복 검사 | SameRecord(...) | 세 열 비교 |
| 삭제 순서 | Step -1 | 아래에서 위로 삭제 |
| 행 삭제 | .Rows(n).Delete | 전표 행 삭제 |
| 반복 사용 | Call RemoveDuplicates(...) | 기준 시트만 바꾸어 재사용 |
자주 묻는 질문 (FAQ)
Q1. 왜 순서도를 먼저 그려야 하나요?
일의 순서를 정립해 두고 시작해야 코딩 중에 헤매지 않으며, 문제를 구체화하면 해결된 것이나 다름없기 때문입니다.
Q2. 셀에 이름을 지정하면 어떤 점이 좋은가요?
기준이 되는 셀이나 영역에 이름을 붙여 두면 프로그래밍에서 위치를 편리하게 참조할 수 있어 권장하는 방법입니다.
Q3. 행을 삭제할 때는 왜 아래에서 위로 반복하나요?
행을 삭제하면 아래 행이 위로 올라와 번호가 바뀌므로, 아래에서 위로 검사해야 건너뛰는 행이 생기지 않습니다.
마치며
"구체화된 문제는 해결된 것이나 다름없다"는 사실을 꼭 기억해 두시기 바랍니다.