매달 복사하던 보고서 자료를 Power Query로 묶고 입력 오류까지 확인하기

월별 파일을 자동으로 합칠 수 있어도, 새 파일의 amount 열이 total로 바뀌거나 금액 단위가 ‘원’에서 ‘천원’으로 달라지면 보고값은 틀릴 수 있어요. 이번에는 정상 입력의 결합 결과와 차단한 파일 목록을 함께 만드는 월간 집계를 만들어요. 새로고침이 끝났다는 사실과 전체 기간의 자료가 준비됐다는 판단을 구분하는 것이 목표예요.

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

예제는 월간 주문 자료를 합치는 담당자를 가정해 만든 합성 CSV예요. 날짜와 주문 번호는 가상이고, 금액도 계산 확인용이에요. Power Query의 폴더 결합은 같은 구조의 여러 파일을 하나의 표로 만드는 기능이에요. 예제 파일의 변환 과정이 다른 파일에도 적용되므로 파일마다 구조가 같은지 먼저 확인해야 해요. Microsoft의 파일 결합 안내에서 기본 동작을 확인할 수 있어요.

월별 보고서 파일을 결합하기 전에 입력 형식을 검사하는 장면
설명 삽화 1. 자동 결합 앞에 열·단위·월 형식 검사를 두면 잘못된 파일을 조용히 섞는 일을 줄일 수 있어요.

입력 규칙을 먼저 고정해요

이번 입력 폴더에는 월별 파일만 넣어요. 열 순서는 month, order_id, amount, unit이고, 한 행은 한 달의 주문 한 건이에요. month는 2026년의 YYYY-MM, 파일명은 같은 월의 YYYY-MM.csv예요. amount는 0 이상의 정수 원화, unit은 KRW로 제한해요. 같은 달의 같은 주문 번호는 한 번만 나타나야 해요.

이 규칙은 모든 조직의 표준이 아니라 이번 보고서의 입력 계약이에요. 열 순서가 달라도 허용하고 싶다면 검사 코드를 바꿀 수 있지만, 바꾸기 전후의 규칙을 기록해야 해요. 한 폴더에 수정본과 구본을 함께 두면 같은 주문을 두 번 계산할 수 있으므로, 채택한 월별 파일만 입력 폴더에 두고 원본 보관 위치는 따로 관리해요.

파일 내용 처리
1월 (ZIP: 2026-01.csv) 100원·150원, 정상 두 행 합계 250 허용
2월 (ZIP: 2026-02.csv) 200원·120원, 정상 두 행 합계 320 허용
3월 (ZIP: 2026-03.csv) amount 대신 total 파일 전체 차단
4월 (ZIP: 2026-04.csv) 금액 1·2, 단위 ‘천원’ 파일 전체 차단
5월 (ZIP: 2026-05.csv) 나중에 추가할 50원·80원 합계 130 허용

3월 total을 보고 마음대로 이름만 바꾸지 않아요. 주문 총액인지 세금 포함 금액인지 확인이 필요해요. 4월도 1,000을 곱하면 될 것 같지만, 이번 입력 규칙을 위반한 파일을 자동으로 보정하지 않아요. 데이터 소유자에게 의미를 확인하고 변환이 승인된 경우에만 별도 규칙을 넣어요.

다섯 월별 파일의 열과 단위를 검사해 3월 열 이름 오류와 4월 단위 오류를 차단하는 입력 목록
그림 1. 제공 계산 예제의 브라우저 화면이에요. 오류가 있는 행만 몰래 버리지 않고 파일 단위로 보류해요.

월 형식은 정상 파일과 반례를 함께 검사해요

월 검사는 접두어가 2026-이고 끝 두 자리가 01~12라는 조건만으로는 부족했어요. 실제 점검에서 2026-extra01도 통과하는 오류를 확인해 수정했어요. 이제 M 코드 (ZIP: combine-example.m)는 2026-01부터 2026-12까지 정해 둔 값과 문자열 전체가 같은지 확인하고 파일명 전체가 해당 월에 .csv를 붙인 이름과 같은지도 대조해요. 2026-01.backup.csv처럼 첫 점 앞부분만 맞는 이름은 허용하지 않아요. 값의 포함 여부는 Microsoft의 List.Contains 문서를 기준으로 구현했어요.

정상 2026-01·2026-12와 비정상 10개를 같은 입력으로 Excel 16.0과 Python 양쪽에서 실행했어요. 2026-extra01, 2026-1, 2026-00, 2026-13, 2026-01x, 2026-001, 전각 숫자를 쓴 2026-01, 다른 연도 2027-01을 차단하고, 월 값은 정상이지만 파일명이 2026-01.backup.csv·2026-02.extra.csv인 두 경우도 차단하는 검사예요. 이번 예제의 계약은 2026년으로 한정하므로 다른 연도를 허용하려면 계약과 양쪽 검사부터 바꿔야 해요.

검사 묶음 허용 차단 허용 합계
월·파일명 검사 12개 2파일·2행 10파일 300원
기존 월별 예제 3파일·6행 2파일 700원

검사 입력·정답 (ZIP: expected.json), Python 결과 (ZIP: month-contract-python.json), 실제 Excel 결과 (ZIP: month-contract-excel.json)와 검사 통합문서 (ZIP: month-contract-excel.xlsx)를 함께 남겼어요. 반례 파일은 별도 폴더에 두어 월별 실습 입력과 섞이지 않아요. 두 검사는 합성 자료의 입력 형식과 예제 결과를 확인하며 실제 회사 원장의 정확성까지 보장하지는 않아요.

‘오류 건너뛰기’ 뒤에 빠진 자료를 남겨요

Power Query에는 오류 파일을 건너뛰는 선택지가 있지만, 결과에서 빠진 파일을 보지 않으면 일부 합계를 전체 합계로 오해하기 쉬워요. 이 예제에서는 파일마다 같은 검사를 수행하고, 성공한 결과는 Accepted, 실패한 파일명과 사유는 Rejected로 분리해요.

제공 M 쿼리 (ZIP: combine-example.m)의 Root는 입력 CSV 폴더를 가리켜요. __ASSET_ROOT__를 자기 컴퓨터의 assets 절대 경로로 바꿔요. Windows 경로라면 C:\작업\R09\assets처럼 넣으면 돼요. Folder.Contents로 바로 아래 CSV만 읽고, 열·빈 파일·단위·월·금액·중복 키를 검사해요. 예제의 월 검사 범위는 2026년이므로 다음 해에 쓸 때는 이 조건도 바꿔야 해요.

Excel에서 빈 쿼리를 만들고 고급 편집기에 M 파일 내용을 붙여 InputAudit라는 이름으로 저장해요. 결과는 여러 표를 가진 레코드예요. 별도의 빈 쿼리 두 개에 각각 아래 식을 넣고 시트에 불러오면 정상 결과와 오류 목록을 나눠 볼 수 있어요.

= InputAudit[Accepted]
= InputAudit[Rejected]

InputAudit[Status]는 차단 파일이 있으면 blocked_incomplete_months예요. 이 상태에서는 정상 결과를 임시 분석에 사용할 수 있지만 전체 기간 보고는 보류해요. 여러 파일에 같은 월·주문 번호가 나타나는 경우 M 쿼리는 결합 단계 자체를 중단해요. 어느 복사본이 정본인지 모르는 상태에서 먼저 읽힌 값을 확정하지 않기 위한 선택이에요.

새 월을 넣어도 같은 검사를 반복해요

처음에는 1~4월 네 파일만 있다고 가정해요. 1·2월의 정상 결과가 4행·570원이고, 3·4월 두 파일이 차단돼요. 여기에 5월 파일을 추가하면 6행·700원이 돼요. 같은 입력으로 한 번 더 실행해도 6행·700원이어야 해요. 기존 결과 뒤에 새 결과를 덧붙이는 방식이 아니라 입력 폴더에서 결과를 다시 만드는 방식이기 때문이에요.

실행 정상 행 수 정상 합계 차단 파일 수 보고 상태
1~4월 입력 4 570원 2 전체 보고 보류
5월 추가 6 700원 2 전체 보고 보류
동일 입력 재실행 6 700원 2 전체 보고 보류
최초 570원에서 5월 추가 뒤 700원으로 바뀌고 재실행 뒤에도 700원을 유지하는 결과 표와 월별 합계
그림 2. 700원은 1·2·5월의 부분 합계예요. 3·4월을 0원으로 처리한 전체 합계가 아니에요.
도착하지 않은 월과 오류로 제외된 파일을 구분하는 장면
설명 삽화 2. 미도착 자료와 오류로 차단한 자료는 원인이 달라요. 일부 결과가 나왔다고 전체 완료로 처리하지 않아요.

Python 3.12.3 표준 라이브러리로 검증 코드 (ZIP: verify.py)를 실행해 위 결과와 차단 사유를 확인했어요. Windows Excel 16.0의 새 테스트 통합문서에서도 Power Query를 실행해 정상 6행과 오류 2파일을 확인했어요. 실행한 통합문서 (ZIP: excel-verified.xlsx)와 실행 증거 (ZIP: evidence.json)에 남겼고, Python 결과와 값·사유를 대조했어요. Excel이 없는 환경에서는 python3 assets/verify.py를 실행하고 정상 결과 (ZIP: accepted.csv), 차단 목록 (ZIP: rejected.csv), 세 번의 실행 비교 (ZIP: run-comparison.csv)를 열어 같은 산술 결과를 확인할 수 있어요. 자기 파일을 넣는 경우 예제의 고정 기대값 검사는 자기 원본 기준으로 변경해야 해요.

검증 코드는 입력 폴더 밖에 결과를 저장해요. 결과 CSV까지 입력 폴더에 넣으면 다음 실행 때 결과를 다시 읽는 순환이 생길 수 있어요. 새 파일이 아예 오지 않은 달은 파일 내부 검사만으로 알 수 없다는 한계도 있어요. 실제 보고에서는 ‘이번 집계에 필요한 월 목록’과 발견한 파일 목록을 대조하는 검사를 추가해야 해요. 예를 들어 1~5월 보고라면 월별 5파일이 있어야 하고, 모두 유효해야 완료예요.

이번 예제의 차단 파일을 바로잡을 때는 사유를 적은 정정본으로 교체한 뒤 전체 결합을 다시 실행해요. 부분 결과에 손으로 3·4월 숫자를 붙이면 다음 새로고침에서 그 수정이 사라질 수 있어요. 병합까지 추가할 계획이라면 중복 키와 합계 검증의 거래별 보존 검사도 연결해 보세요. 원고·합성 입력·검증 코드는 2026년 10월 13일 Codex가 작성했어요.

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

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

python3 replay.py

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

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