두 자료를 합쳤더니 합계가 늘었다: Excel 병합의 중복 키와 누락 행 잡기

거래표에 담당 부서를 붙였을 뿐인데 금액 합계가 500에서 750으로 늘었어요. 이런 상황에서는 합계 함수를 고치기 전에, 거래 한 건이 기준표 몇 행과 연결됐는지 확인해야 해요. 이번 글에서는 거래를 지우지 않고 원본 5행·합계 500을 보존하면서 미확정 부서를 따로 남기는 병합표를 만들어요.

첨부 링크는 이 글의 예제 ZIP으로 연결돼요. 압축을 푼 뒤 링크에 표시된 파일을 열면 입력·코드·완성 자료를 함께 사용할 수 있어요.

예제는 설명을 위해 만든 합성 자료예요. 실제 매출이나 저자의 업무 경험은 아니에요. 금액 단위는 원으로 통일했고, 한 행은 거래 한 건이에요. 거래번호는 유일하지만 같은 고객은 여러 번 거래할 수 있어요. 따라서 필요한 관계는 ‘여러 거래 → 고객당 하나의 담당 부서’예요.

같은 키가 여러 행에 있어 병합 결과가 늘어나는 모습
설명 삽화 1. 병합 뒤 합계가 늘었다면 키가 한 번만 나타나는지부터 확인해요.

합계 250이 어디에서 늘었는지 찾아봐요

거래표 (ZIP: transactions.csv)에는 T1/A/100, T2/B/200, T3/B/50, T4/C/80, T5/D/70이 있어요. 기준표 (ZIP: reference.csv)에는 A/영업, B/동부, B/서부, C/연구가 있어요. B의 담당 부서가 둘이고, D는 기준표에 없어요. 여기서 B가 중복이라는 이유만으로 거래 T2나 T3를 지우면 정상 거래가 사라져요. 문제는 거래번호가 아니라 담당 부서를 하나로 결정해야 하는 기준표의 고객 키에 있어요.

Power Query 병합은 지정한 열의 값으로 두 표를 연결하고, 연결된 표 열을 확장할 수 있어요. 여러 열을 키로 쓸 때는 두 표의 열 선택 순서와 데이터 형식도 맞춰야 해요. 이 기능의 동작은 Microsoft 병합 안내에서 확인할 수 있어요.

고객 ID만으로 왼쪽 외부 병합한 뒤 부서를 확장하면 결과는 다음처럼 돼요.

거래 고객 원본 금액 확장된 부서 결과 금액
T1 A 100 영업 100
T2 B 200 동부·서부에 각각 연결 400
T3 B 50 동부·서부에 각각 연결 100
T4 C 80 연구 80
T5 D 70 연결 없음 70

원본의 B 거래 합계가 250이고 기준표의 B가 두 행이므로, B 거래 금액 250이 한 번 더 붙어요. 결과는 7행, 합계 750이에요. 기준표 B가 세 행이었다면 B 거래가 세 번씩 나타나 합계는 1,000이 됐을 거예요. ‘중복이 있다’는 확인보다 어떤 키가 얼마를 증식시켰는지 계산하는 편이 수정 대상을 좁혀줘요.

B 고객의 거래 두 건이 동부와 서부에 각각 연결되어 5행 500이 7행 750으로 늘어난 계산 표
그림 1. 제공 계산 예제의 브라우저 화면이에요. 잘못 확장한 결과 CSV와 같은 일곱 행이며, Excel 화면을 흉내 낸 이미지가 아니에요.

첫 행을 남기는 대신 미확정 연결을 보류해요

기준표에서 B의 첫 행만 남기면 행 수와 합계는 정상처럼 보일 수 있어요. 하지만 동부가 맞다는 근거는 생기지 않아요. 이 예제에는 적용 날짜나 공동 담당 비율도 없으므로 B를 어느 한 부서로 결정할 수 없어요. 그래서 다음 기준을 택해요.

  1. 거래번호가 비었거나 중복되면 거래 원본부터 확인해요. 고객 키의 공백·앞자리 0·문자형 변환도 먼저 살펴봐요.
  2. 기준표에서 고객별 행 수를 세어요. 한 행인 A와 C만 확정 연결에 사용해요. B는 별도 중복 목록으로 남겨요.
  3. 거래표 전체를 기준으로 확정 기준표와 왼쪽 외부 병합해요. 중복 목록에 있는 B는 ‘중복키 보류’, 나머지 연결 없는 D는 ‘미연결’로 구분해요.
  4. 거래번호별 행 수, 전체 행 수, 전체 합계, 상태별 합계를 원본과 대조해요.

이렇게 만든 병합표 (ZIP: merged.csv)는 다음과 같아요.

거래 고객 금액 담당 부서 연결 상태
T1 A 100 영업 연결
T2 B 200 미확정 중복키 보류
T3 B 50 미확정 중복키 보류
T4 C 80 연구 연결
T5 D 70 미확정 미연결

확정 부서 금액 180, 중복키 보류 250, 미연결 70을 더하면 원본 500과 같아요. ‘분류가 끝난 매출 500’이라고 보고하면 안 되고, 전체 500 중 부서 분류가 끝난 금액은 180이라고 써야 해요. 예외 목록 (ZIP: exceptions.csv)에 T2·T3·T5를 남겨 기준표 담당자에게 확인할 수도 있어요.

원본 다섯 거래를 보존한 병합표와 확정 180, 중복키 보류 250, 미연결 70의 합계 대조
그림 2. 전체 합계가 맞아도 분류가 끝난 것은 아니에요. 미확정 금액을 따로 표시한 계산 결과예요.
정상 결합 자료와 매칭되지 않은 자료를 나누어 대조하는 장면
설명 삽화 2. 결합 결과뿐 아니라 누락 행과 병합 전후 합계까지 함께 대조해야 해요.

Excel로 옮길 때도 같은 검사를 남겨요

실행한 예제는 두 CSV를 같은 폴더 원본으로 읽어요. M 쿼리 (ZIP: merge-example.m)를 열고 __ASSET_ROOT__를 두 CSV가 있는 assets 폴더의 절대 경로로 바꿔요. Excel에서 빈 쿼리를 만들고 고급 편집기에 전체 코드를 붙인 뒤 MergeAudit라는 이름으로 저장해요. 이 쿼리는 Folder.Contents에서 두 파일을 찾아 읽고, 중복 고객을 분리한 뒤 거래 전체를 왼쪽 외부 병합해요.

별도 빈 쿼리의 수식에 = MergeAudit[Merged]를 넣어 병합표를 불러오고, 다른 빈 쿼리에는 = MergeAudit[Exceptions]를 넣어 보류 목록을 불러와요. 내부 연결만 쓰면 D 같은 거래가 사라질 수 있어요. 기준표를 바꾸기 전에는 결과 시트의 행을 손으로 삭제하지 않아요.

Windows Excel 16.0의 새 테스트 통합문서에서 두 쿼리를 실행해 병합표 5행과 예외 3행을 확인했어요. 실행한 통합문서 (ZIP: excel-verified.xlsx)와 실행 증거 (ZIP: evidence.json)를 함께 제공해요. 최초에는 두 파일을 개별 원본으로 읽다가 개인정보 수준 지정을 요구받았어요. 계정 설정을 바꾸지 않고 단일 폴더 원본으로 구성해 다시 실행했어요. 자기 환경에서도 원본 접근 설정이 요구되면 조직의 설정 기준에 맞춰 처리하고, 출처가 다른 업무 자료의 보호 설정을 일괄 해제하지는 마세요. Excel이 없으면 다음 명령으로 같은 결과 CSV를 다시 만들 수 있어요.

python3 assets/verify.py

Python 3.12.3의 표준 라이브러리로 실행했고 추가 패키지는 필요 없어요. 결과 파일 results.json (ZIP: results.json)에서 safe_rows=5, safe_total=500, duplicate_hold=250, unmatched=70을 확인해요. 코드의 검사는 행 수·합계뿐 아니라 상태별 금액도 대조해요. 다른 자료에 쓰려면 입력 CSV를 바꾸고 예제의 고정 기대값 검사도 자기 원본의 값으로 바꿔야 해요. pandas를 쓴다면 validate="many_to_one"으로 오른쪽 키의 유일성을 검사할 수 있어요. 이 옵션의 정확한 검사 범위는 pandas 공식 문서에 나와 있어요.

B가 실제로 두 부서에 나눠 귀속되는 거래라면 지금 방법으로 최종 배분할 수 없어요. 거래일에 맞는 유효 기간을 키에 더하거나, 합계가 1이 되는 배분율 표를 만들어야 해요. 반대로 완전히 같은 행의 중복이라면 어느 입력 과정에서 반복됐는지 확인한 뒤 기준표만 정리할 수 있어요. 행 수와 합계가 보존되는지, 부서 배정의 근거가 있는지는 별개의 검사로 남겨주세요.

합친 뒤 보고값이 계속 다르다면 지표 정의서로 분모와 기간 맞추기에서 집계 기준도 확인해 보세요. 원고와 합성 계산은 2026년 10월 13일 Codex가 작성·실행했으며, 실제 조직의 키 체계와 담당 부서 판정은 포함하지 않았어요.

예제 파일을 한 번에 받아 다시 확인해요

이 글의 입력·코드·완성 자료 ZIP을 새 폴더에 풀면 R07/README.txt, replay.py, assets 폴더가 함께 생겨요. 개별 코드 파일만 저장하면 보조 모듈이나 입력이 빠질 수 있으므로 처음에는 이 묶음을 사용하세요. R07 폴더에서 다음 명령을 실행하면 본문에 사용한 검사를 순서대로 수행해요.

python3 replay.py

확인할 결과는 원본5행·합계500 유지, 미확정 관계 분리예요. 명령이 성공해도 이 값과 본문의 적용 범위를 함께 대조하세요. 실행 안내 (ZIP: README.txt)에 필요한 파일과 개별 명령을 적었어요. 실행 코드는 verify.py (ZIP: verify.py)에서 직접 볼 수 있어요. Python3.12의 표준 라이브러리를 사용하며, 명령이 실패하면 ZIP의 폴더 구조와 오류에 나온 파일부터 확인해요. 실제 앱 실행에 필요한 프로그램은 원래 설명을 따르세요.

설명 삽화 2장은 GPT로 생성한 개념 설명이에요. 실제 예제의 작업 화면과 실행 결과는 기존 그림·첨부 자료에서 따로 확인할 수 있어요.