TL;DR
- Excel 테이블 변경 추적을 수작업에서 자동화로: Refresh 한 번에 Added/Removed/Modified 판별
- RowHash 기반 스냅샷 비교로 중복 키, 행 순서 변경에도 정확한 결과
- 회계 실무 확장: 예산 vs 실적, MoM/YoY 비교, 원가 분석, 감사 추적에 즉시 적용 가능
- 재사용 가능한 Power Query 템플릿 제공
실무 문제: 왜 이 자동화가 필요했나
회계 실무에서 반복되는 고통스러운 시나리오:
월말 마감 시점
– 오더북 배포본과 회수본 비교
– “어떤 발주가 추가됐지?”
– “수량이나 금액이 바뀐 건 뭐지?”
– “삭제된 항목은?”
기존 방식의 한계
– VLOOKUP으로 매칭 → 중복 발주번호 처리 어려움
– 조건부 서식으로 눈으로 확인 → 사람 실수 발생
– 수작업 비교 → 시간 오래 걸림, 마감 지연
필요한 것
– 자동으로 변경사항 감지
– 중복 키도 정확하게 처리
– 어떤 열이 어떻게 바뀌었는지 상세 추적
–
그리고 이 로직을 다른 분석에도 재사용
솔루션: RowHash 기반 스냅샷 비교
핵심 아이디어
RowHash란?
각 행의 데이터를 하나의 문자열로 압축한 “지문”
예: 발주번호 PO-001
제품: 밸브A, 수량: 10, 금액: 100,000
→ RowHash: "밸브A|10|100000"
데이터가 바뀌면 RowHash도 바뀜
제품: 밸브A, 수량: 15, 금액: 150,000
→ RowHash: "밸브A|15|150000"
비교 로직
1. 배포 전/후 테이블 각각에 RowHash 생성
2. 발주번호 + 중복인덱스로 양쪽 테이블 병합 (Full Outer Join)
3. RowHash 비교로 변경 유형 판별:
–
Removed: 배포 전에만 존재
–
Added: 배포 후에만 존재
–
Unchanged: RowHash 동일
–
Modified: RowHash 다름
4. Modified 행의 경우 열별 변경 내용 상세 추출
실제 구현: Power Query M 코드
사용 예시
배포 전 (P06_Start)
| 발주번호 |
제품명 |
수량 |
금액 |
| PO-001 |
밸브A |
10 |
100,000 |
| PO-002 |
밸브B |
5 |
50,000 |
| PO-002 |
밸브C |
3 |
30,000 |
배포 후 (P06_Ending)
| 발주번호 |
제품명 |
수량 |
금액 |
| PO-001 |
밸브A |
15 |
150,000 |
| PO-002 |
밸브B |
5 |
50,000 |
| PO-003 |
밸브D |
7 |
70,000 |
결과
| 발주번호 |
제품명 |
ChangeType |
수량_Diff |
금액_Diff |
| PO-001 |
밸브A |
Modified |
10 → 15 |
100000 → 150000 |
| PO-002 |
밸브B |
Unchanged |
null |
null |
| PO-002 |
밸브C |
Removed |
null |
null |
| PO-003 |
밸브D |
Added |
null |
null |
코드 템플릿
let
//--------------------------------------------------
// ① 사용자 설정
//--------------------------------------------------
StartName = "P06_Start", // 과거 테이블명
EndName = "P06_Ending", // 현재 테이블명
KeyCols = {"발주번호"}, // 키 열 (복합키는 {"A","B"})
Culture = "ko-KR", // 지역 설정
//--------------------------------------------------
// ② 원본 로드
//--------------------------------------------------
S0 = Excel.CurrentWorkbook(){[Name = StartName]}[Content],
E0 = Excel.CurrentWorkbook(){[Name = EndName ]}[Content],
//--------------------------------------------------
// ③ 중복 인덱스 부여 (같은 키 내 순번 구분)
//--------------------------------------------------
fnAddDupIdx = (tbl as table) as table =>
let
Grouped = Table.Group(
tbl, KeyCols,
{{"AllRows",
(g) => Table.AddIndexColumn(g, "__DupIndex", 1, 1, Int64.Type),
type table}}
),
Recombine = Table.Combine(Grouped[AllRows])
in Recombine,
S1 = fnAddDupIdx(S0),
E1 = fnAddDupIdx(E0),
//--------------------------------------------------
// ④ RowHash 생성
//--------------------------------------------------
AllCols = List.Union({Table.ColumnNames(S1), Table.ColumnNames(E1)}),
NonKeyCols = List.Difference(AllCols, List.Combine({KeyCols, {"__DupIndex"}})),
fnRowHash = (r as record) as text =>
Text.Combine(
List.Transform(
NonKeyCols,
(c) => Text.From(Record.FieldOrDefault(r, c, null), Culture)
),
"|"
),
S = Table.AddColumn(S1, "RowHash", each fnRowHash(_), type text),
E = Table.AddColumn(E1, "RowHash", each fnRowHash(_), type text),
//--------------------------------------------------
// ⑤ Full Outer Join
//--------------------------------------------------
JoinKeys = List.Combine({KeyCols, {"__DupIndex"}}),
Join = Table.NestedJoin(
S, JoinKeys,
E, JoinKeys,
"EndRec",
JoinKind.FullOuter
),
X = Table.ExpandTableColumn(
Join, "EndRec",
Table.ColumnNames(E),
List.Transform(Table.ColumnNames(E), each _ & "_End")
),
//--------------------------------------------------
// ⑥ ChangeType 판별
//--------------------------------------------------
AddStatus = Table.AddColumn(
X, "ChangeType",
(r) =>
let
missEnd = r[RowHash_End] = null,
missStart = r[RowHash] = null,
sameHash = r[RowHash] = r[RowHash_End]
in
if missEnd then "Removed"
else if missStart then "Added"
else if sameHash then "Unchanged"
else "Modified"
),
//--------------------------------------------------
// ⑦ 열별 변경 내용 추출
//--------------------------------------------------
AddDiffCols = Table.AddColumn(
AddStatus, "ChangedCols",
(r) =>
if r[ChangeType] <> "Modified" then null
else List.Select(
NonKeyCols,
(c) =>
let
old = Record.FieldOrDefault(r, c, null),
new = Record.FieldOrDefault(r, c & "_End", null)
in not Value.Equals(old, new)
)
),
AddDiffValues = List.Accumulate(
NonKeyCols, AddDiffCols,
(state, col) =>
Table.AddColumn(
state, col & "_Diff",
each
let
hasChanged = ([ChangedCols] <> null) and
List.Contains([ChangedCols], col),
oldVal = Record.FieldOrDefault(_, col, null),
newVal = Record.FieldOrDefault(_, col & "_End", null),
oldTxt = if oldVal = null then "" else Text.From(oldVal, Culture),
newTxt = if newVal = null then "" else Text.From(newVal, Culture)
in
if hasChanged then oldTxt & " → " & newTxt
else null,
type text
)
),
//--------------------------------------------------
// ⑧ 정리
//--------------------------------------------------
Result = Table.RemoveColumns(AddDiffValues, {"RowHash", "RowHash_End"})
in
Result
실무 확장: 회계 Variance 분석 활용
이 테이블 비교 로직은 단순 오더북 추적을 넘어
회계 실무의 핵심 분석들에 즉시 적용 가능합니다. 각 케이스별로 실제 적용 방법을 상세히 설명합니다.
확장 케이스 1: 예산 vs 실적 분석 (Budget vs Actual)
실무 배경
매월 예산 대비 실적을 분석하는 것은 모든 회계팀의 필수 업무입니다. 하지만 수작업으로 하면:
– 계정과목별로 일일이 비교
– 차이 계산 수작업
– 차이율 계산 실수
– 새로운 계정 추가/삭제 누락
데이터 준비 예시
Budget_2025 테이블
| 계정과목 |
부서 |
예산금액 |
비고 |
| 급여 |
영업팀 |
50,000,000 |
월간 |
| 급여 |
관리팀 |
30,000,000 |
월간 |
| 복리후생비 |
영업팀 |
5,000,000 |
|
| 복리후생비 |
관리팀 |
3,000,000 |
|
| 교육훈련비 |
관리팀 |
2,000,000 |
|
Actual_2025 테이블
| 계정과목 |
부서 |
실적금액 |
비고 |
| 급여 |
영업팀 |
52,000,000 |
초과근무 증가 |
| 급여 |
관리팀 |
29,500,000 |
1명 퇴사 |
| 복리후생비 |
영업팀 |
5,200,000 |
|
| 복리후생비 |
관리팀 |
2,500,000 |
행사 취소 |
| 마케팅비 |
영업팀 |
10,000,000 |
신규 항목 |
Power Query 설정
let
// ① 테이블 지정
StartName = "Budget_2025",
EndName = "Actual_2025",
// ② 키 열 설정 (복합키)
KeyCols = {"계정과목", "부서"},
// ③ 나머지는 기본 템플릿 그대로 사용
Culture = "ko-KR",
// ... (기본 템플릿 로직)
in
Result
출력 결과
| 계정과목 |
부서 |
ChangeType |
예산금액 |
실적금액 |
예산금액_Diff |
실적금액_Diff |
ChangedCols |
| 급여 |
영업팀 |
Modified |
50,000,000 |
52,000,000 |
null |
null |
[“실적금액”,”비고”] |
| 급여 |
관리팀 |
Modified |
30,000,000 |
29,500,000 |
null |
null |
[“실적금액”,”비고”] |
| 복리후생비 |
영업팀 |
Modified |
5,000,000 |
5,200,000 |
null |
null |
[“실적금액”] |
| 복리후생비 |
관리팀 |
Modified |
3,000,000 |
2,500,000 |
null |
null |
[“실적금액”,”비고”] |
| 교육훈련비 |
관리팀 |
Removed |
2,000,000 |
null |
null |
null |
null |
| 마케팅비 |
영업팀 |
Added |
null |
10,000,000 |
null |
null |
null |
추가 분석 컬럼
기본 결과에 차이액, 차이율을 자동 계산하는 컬럼을 추가합니다:
// Result 테이블에 추가 분석 컬럼 생성
// 1) 차이액 계산
AddVariance = Table.AddColumn(
Result, "차이액",
each
if [ChangeType] = "Modified" then
[실적금액_End] - [예산금액]
else if [ChangeType] = "Added" then
[실적금액_End]
else if [ChangeType] = "Removed" then
-[예산금액]
else null,
type number
),
// 2) 차이율 계산 (%)
AddVarianceRate = Table.AddColumn(
AddVariance, "차이율(%)",
each
if [ChangeType] = "Modified" and [예산금액] <> 0 then
Number.Round(([실적금액_End] - [예산금액]) / [예산금액] * 100, 1)
else null,
type number
),
// 3) 중요도 플래그 (차이율 절대값 10% 이상)
AddFlag = Table.AddColumn(
AddVarianceRate, "주의필요",
each
if [차이율(%)] <> null and Number.Abs([차이율(%)]) >= 10 then
"⚠️ 중요"
else null,
type text
)
최종 결과 (분석 컬럼 포함)
| 계정과목 |
부서 |
ChangeType |
예산금액 |
실적금액 |
차이액 |
차이율(%) |
주의필요 |
| 급여 |
영업팀 |
Modified |
50,000,000 |
52,000,000 |
+2,000,000 |
+4.0 |
null |
| 급여 |
관리팀 |
Modified |
30,000,000 |
29,500,000 |
-500,000 |
-1.7 |
null |
| 복리후생비 |
영업팀 |
Modified |
5,000,000 |
5,200,000 |
+200,000 |
+4.0 |
null |
| 복리후생비 |
관리팀 |
Modified |
3,000,000 |
2,500,000 |
-500,000 |
-16.7 |
⚠️ 중요 |
| 교육훈련비 |
관리팀 |
Removed |
2,000,000 |
null |
-2,000,000 |
null |
null |
| 마케팅비 |
영업팀 |
Added |
null |
10,000,000 |
+10,000,000 |
null |
null |
경영진 보고용 피벗 테이블
이 결과를 피벗 테이블로 요약:
부서별 예산 집행률
| 부서 |
예산 합계 |
실적 합계 |
차이액 |
집행률(%) |
| 영업팀 |
55,000,000 |
67,200,000 |
+12,200,000 |
122.2 |
| 관리팀 |
35,000,000 |
32,000,000 |
-3,000,000 |
91.4 |
주의 필요 항목 필터
– 복리후생비(관리팀): -16.7% (행사 취소로 절감)
– 마케팅비(영업팀): 예산 없이 10백만원 집행 (신규)
확장 케이스 2: 기간 비교 분석 (MoM / YoY)
실무 배경
매출 트렌드 분석에서 가장 중요한 것은 전월(MoM) 또는 전년 동기(YoY) 대비 변동입니다.
– 어떤 제품이 성장하고 있는가?
– 어떤 지역에서 매출이 감소하는가?
– 신규 제품/중단 제품은?
데이터 준비 예시 (MoM)
Sales_202409 테이블 (9월)
| 제품코드 |
지역 |
매출액 |
판매량 |
| PROD-A |
서울 |
100,000,000 |
1,000 |
| PROD-A |
부산 |
50,000,000 |
500 |
| PROD-B |
서울 |
80,000,000 |
800 |
| PROD-B |
부산 |
40,000,000 |
400 |
| PROD-C |
서울 |
30,000,000 |
300 |
Sales_202410 테이블 (10월)
| 제품코드 |
지역 |
매출액 |
판매량 |
| PROD-A |
서울 |
120,000,000 |
1,200 |
| PROD-A |
부산 |
45,000,000 |
450 |
| PROD-B |
서울 |
85,000,000 |
850 |
| PROD-B |
부산 |
42,000,000 |
420 |
| PROD-D |
서울 |
50,000,000 |
500 |
Power Query 설정
let
// MoM 분석
StartName = "Sales_202409", // 9월 (과거)
EndName = "Sales_202410", // 10월 (현재)
KeyCols = {"제품코드", "지역"},
Culture = "ko-KR",
// ... (기본 템플릿)
in
Result
추가 분석: 성장률 계산
// 매출 성장률
AddSalesGrowth = Table.AddColumn(
Result, "매출성장률(%)",
each
if [ChangeType] = "Modified" and [매출액] <> 0 then
Number.Round(([매출액_End] - [매출액]) / [매출액] * 100, 1)
else if [ChangeType] = "Added" then
null // 신규는 성장률 계산 불가
else null,
type number
),
// 판매량 성장률
AddQtyGrowth = Table.AddColumn(
AddSalesGrowth, "판매량성장률(%)",
each
if [ChangeType] = "Modified" and [판매량] <> 0 then
Number.Round(([판매량_End] - [판매량]) / [판매량] * 100, 1)
else null,
type number
),
// 트렌드 분류
AddTrend = Table.AddColumn(
AddQtyGrowth, "트렌드",
each
if [ChangeType] = "Added" then "🆕 신규"
else if [ChangeType] = "Removed" then "❌ 중단"
else if [매출성장률(%)] >= 10 then "📈 고성장"
else if [매출성장률(%)] >= 0 then "➡️ 안정"
else if [매출성장률(%)] >= -10 then "📉 주의"
else "🚨 급감"
,
type text
)
최종 결과
| 제품코드 |
지역 |
ChangeType |
9월매출 |
10월매출 |
매출성장률(%) |
판매량성장률(%) |
트렌드 |
| PROD-A |
서울 |
Modified |
100,000,000 |
120,000,000 |
+20.0 |
+20.0 |
📈 고성장 |
| PROD-A |
부산 |
Modified |
50,000,000 |
45,000,000 |
-10.0 |
-10.0 |
📉 주의 |
| PROD-B |
서울 |
Modified |
80,000,000 |
85,000,000 |
+6.3 |
+6.3 |
➡️ 안정 |
| PROD-B |
부산 |
Modified |
40,000,000 |
42,000,000 |
+5.0 |
+5.0 |
➡️ 안정 |
| PROD-C |
서울 |
Removed |
30,000,000 |
null |
null |
null |
❌ 중단 |
| PROD-D |
서울 |
Added |
null |
50,000,000 |
null |
null |
🆕 신규 |
YoY 분석 (동일 로직)
// YoY 분석
StartName = "Sales_202310", // 2023년 10월
EndName = "Sales_202410", // 2024년 10월
KeyCols = {"제품코드", "지역"},
계절성 패턴, 연간 성장 추세를 파악하는 데 활용합니다.
확장 케이스 3: 원가 분석 (Standard vs Actual Cost)
실무 배경
제조업에서 가장 중요한 관리회계 업무 중 하나가 원가 차이 분석입니다:
– 표준원가 대비 실제원가 차이가 얼마나 발생했는가?
– 어떤 원가 요소(재료비, 노무비, 경비)에서 차이가 큰가?
– 수량 차이인가, 가격 차이인가?
데이터 준비 예시
StandardCost 테이블
| 제품코드 |
재료비(표준) |
노무비(표준) |
제조경비(표준) |
표준수량 |
표준단가 |
| PROD-001 |
1,000 |
500 |
200 |
100 |
1,700 |
| PROD-002 |
2,000 |
800 |
300 |
50 |
3,100 |
| PROD-003 |
1,500 |
600 |
250 |
80 |
2,350 |
ActualCost 테이블
| 제품코드 |
재료비(실제) |
노무비(실제) |
제조경비(실제) |
실제수량 |
실제단가 |
| PROD-001 |
1,200 |
480 |
220 |
110 |
1,900 |
| PROD-002 |
1,950 |
820 |
310 |
48 |
3,080 |
| PROD-003 |
1,600 |
650 |
270 |
85 |
2,520 |
Power Query 설정
let
StartName = "StandardCost",
EndName = "ActualCost",
KeyCols = {"제품코드"},
Culture = "ko-KR",
// ... (기본 템플릿)
in
Result
고급 분석: Variance 세분화
제조 원가 분석의 핵심은
수량 차이와
가격 차이를 분리하는 것입니다:
// 1) 재료비 수량 차이 (Material Quantity Variance)
AddMQV = Table.AddColumn(
Result, "재료비_수량차이",
each
if [ChangeType] = "Modified" then
([실제수량_End] - [표준수량]) * [표준단가]
else null,
type number
),
// 2) 재료비 가격 차이 (Material Price Variance)
AddMPV = Table.AddColumn(
AddMQV, "재료비_가격차이",
each
if [ChangeType] = "Modified" then
([실제단가_End] - [표준단가]) * [실제수량_End]
else null,
type number
),
// 3) 총 원가 차이
AddTotalVar = Table.AddColumn(
AddMPV, "총원가차이",
each
if [ChangeType] = "Modified" then
([재료비(실제)_End] + [노무비(실제)_End] + [제조경비(실제)_End]) -
([재료비(표준)] + [노무비(표준)] + [제조경비(표준)])
else null,
type number
),
// 4) 차이 분류
AddVarType = Table.AddColumn(
AddTotalVar, "차이유형",
each
if [총원가차이] = null then null
else if [총원가차이] > 0 then "🔴 불리한 차이"
else if [총원가차이] < 0 then "🟢 유리한 차이"
else "⚪ 차이 없음",
type text
)
최종 결과
| 제품코드 |
ChangeType |
표준원가 |
실제원가 |
재료비_수량차이 |
재료비_가격차이 |
총원가차이 |
차이유형 |
| PROD-001 |
Modified |
1,700 |
1,900 |
+170 |
+2,200 |
+200 |
🔴 불리한 차이 |
| PROD-002 |
Modified |
3,100 |
3,080 |
-310 |
-96 |
-20 |
🟢 유리한 차이 |
| PROD-003 |
Modified |
2,350 |
2,520 |
+235 |
+425 |
+170 |
🔴 불리한 차이 |
인사이트
PROD-001 분석
– 총원가차이: +200 (불리)
– 수량차이: +170 (실제 110개 vs 표준 100개)
– 가격차이: +2,200 (실제 단가 상승)
–
조치: 재료 구매 단가 협상 필요
PROD-002 분석
– 총원가차이: -20 (유리)
– 수량차이: -310 (실제 48개 vs 표준 50개, 효율 향상)
– 가격차이: -96 (재료비 절감)
–
평가: 공정 개선 효과 확인
확장 케이스 4: 감사 추적 (Audit Trail)
실무 배경
SOX 법규 준수 또는 내부 통제를 위해
데이터 변경 이력을 추적해야 하는 경우:
– 재무제표 수정 내역
– 재고 수량 변경 기록
– 고정자산 변동 이력
데이터 준비
FixedAssets_Before (마감 전)
| 자산번호 |
자산명 |
취득가액 |
감가상각누계액 |
장부가액 |
담당부서 |
| FA-001 |
서버장비 |
10,000,000 |
6,000,000 |
4,000,000 |
IT팀 |
| FA-002 |
차량 |
30,000,000 |
15,000,000 |
15,000,000 |
영업팀 |
| FA-003 |
사무기기 |
5,000,000 |
3,000,000 |
2,000,000 |
관리팀 |
FixedAssets_After (마감 후)
| 자산번호 |
자산명 |
취득가액 |
감가상각누계액 |
장부가액 |
담당부서 |
| FA-001 |
서버장비 |
10,000,000 |
6,200,000 |
3,800,000 |
IT팀 |
| FA-002 |
차량 |
30,000,000 |
15,500,000 |
14,500,000 |
영업팀 |
| FA-004 |
복합기 |
3,000,000 |
0 |
3,000,000 |
관리팀 |
Power Query 설정
let
StartName = "FixedAssets_Before",
EndName = "FixedAssets_After",
KeyCols = {"자산번호"},
Culture = "ko-KR",
// ... (기본 템플릿)
// 감사 추적용 메타데이터 추가
AddAuditMeta = Table.AddColumn(
Result, "검증일시",
each DateTime.LocalNow(),
type datetime
),
AddUser = Table.AddColumn(
AddAuditMeta, "검증자",
each Environment.UserName,
type text
),
// 변경 중요도 플래그
AddSeverity = Table.AddColumn(
AddUser, "중요도",
each
if [ChangeType] = "Added" then "🆕 신규 취득"
else if [ChangeType] = "Removed" then "⚠️ 폐기/매각"
else if [ChangedCols] <> null and
List.Contains([ChangedCols], "취득가액") then
"🚨 취득가액 수정"
else if [ChangedCols] <> null and
List.Contains([ChangedCols], "감가상각누계액") then
"📝 정상 감가상각"
else "ℹ️ 기타 변경",
type text
)
in
AddSeverity
최종 감사 리포트
| 자산번호 |
자산명 |
ChangeType |
ChangedCols |
중요도 |
검증일시 |
검증자 |
| FA-001 |
서버장비 |
Modified |
[“감가상각누계액”,”장부가액”] |
📝 정상 감가상각 |
2025-10-04 15:30 |
bjt |
| FA-002 |
차량 |
Modified |
[“감가상각누계액”,”장부가액”] |
📝 정상 감가상각 |
2025-10-04 15:30 |
bjt |
| FA-003 |
사무기기 |
Removed |
null |
⚠️ 폐기/매각 |
2025-10-04 15:30 |
bjt |
| FA-004 |
복합기 |
Added |
null |
🆕 신규 취득 |
2025-10-04 15:30 |
bjt |
감사 대응 활용
1) 외부 감사 대응
– “FA-003이 왜 사라졌나요?” → Removed 확인, 폐기 승인 문서와 매칭
– “FA-004는 언제 추가됐나요?” → Added 확인, 검증일시 제공
2) 내부 통제
– 취득가액 수정이 발생하면 “🚨 취득가액 수정” 플래그로 즉시 감지
– 정기 감가상각은 “📝 정상 감가상각”으로 필터링하여 제외
3) 컴플라이언스 리포트 자동 생성
// 중요 변경 사항만 필터링
Table.SelectRows(
AddSeverity,
each [중요도] = "🚨 취득가액 수정" or
[중요도] = "⚠️ 폐기/매각" or
[중요도] = "🆕 신규 취득"
)
실무 적용 시 체크리스트
확장 적용 전 확인사항
- 데이터 품질
- [ ] 테이블에 중복 데이터 없는지 확인
- [ ] 키 열에 null 값 없는지 확인
- [ ] 숫자 필드가 텍스트로 저장되지 않았는지 확인
- 키 열 선정
- [ ] 단일 키로 충분한가? 복합 키가 필요한가?
- [ ] 키 열 조합이 고유성을 보장하는가?
- 비교 범위
- [ ] 모든 열을 비교해야 하는가?
- [ ] 제외해야 할 열이 있는가? (예: 타임스탬프, 시스템 생성 ID)
- 성능 고려
- [ ] 테이블 크기가 적절한가? (수만 행 이상이면 데이터베이스 활용 고려)
- [ ] Refresh 시간이 허용 범위인가?
확장 시 추천 순서
- 오더북 비교 (기본) → 로직 숙지
- 예산 vs 실적 (단순 확장) → 분석 컬럼 추가 연습
- MoM/YoY (시계열) → 피벗 테이블 활용
- 원가 분석 (고급) → Variance 세분화
- 감사 추적 (메타데이터) → 컴플라이언스 리포트
실무 적용 가이드
Step 1: 파일 준비
- Excel 파일에 비교할 두 테이블 생성
- 테이블 이름 지정 (예: “Budget_2025”, “Actual_2025”)
- 중요: 깨끗한 데이터 사용 (숨겨진 서식 제거)
Step 2: Power Query 편집기
- Excel → 데이터 탭 → “데이터 가져오기” → “기타 원본에서” → “빈 쿼리”
- 고급 편집기 열기
- 위 템플릿 코드 붙여넣기
- 설정 섹션 수정 (테이블명, 키 열)
Step 3: 실행 및 확인
- “닫기 및 로드”
- 결과 테이블 확인
- 피벗 테이블로 요약 분석
Troubleshooting: 모든 행이 “Modified”로 나올 때
증상: 육안으로 동일한 데이터인데 전부 Modified
원인
– Excel 테이블의 숨겨진 서식/메타데이터 오염
– Power Query 캐시 문제
– 보이지 않는 공백 문자
해결책
1. 새 Excel 파일 생성
2. 두 테이블을
값으로만 복사 (Ctrl+Alt+V → 값)
3. 새 테이블로 다시 Power Query 실행
교훈: Power Query 결과가 이상하면 데이터 자체보다 컨테이너(테이블 객체) 문제일 수 있음
Power Query vs SQL: 개념적 유사성
회계 실무자들은 SQL을 모르는 경우가 많지만, Power Query는 “비주얼 SQL”입니다.
| SQL |
Power Query |
설명 |
| SELECT |
열 선택 UI |
필요한 컬럼만 |
| WHERE |
Table.SelectRows |
조건 필터링 |
| JOIN |
Table.NestedJoin |
테이블 병합 |
| GROUP BY |
Table.Group |
그룹화/집계 |
| CASE WHEN |
if…then…else |
조건부 로직 |
| WITH CTE |
let…in |
중간 결과 저장 |
장점
– 시각적 피드백: 각 단계별 즉시 확인
– Undo 가능: 실수해도 쉽게 되돌리기
– Excel과 자연스러운 통합
마무리: AI 시대, 회계사의 생존 전략
이 프로젝트가 증명하는 것
AI는 도메인 없이는 쓸모없다
– GPT가 오더북 마감 프로세스를 이해할 수 없다
– “중복 발주번호가 왜 문제인지” AI는 모른다
– “마감 자료 변동 체크”의 중요성도 모른다
회계사 + AI = 진짜 가치
– 회계사: 문제 정의, 도메인 지식
– AI (Power Query/Python): 자동화, 확장
– 결과: 마감 시간 3시간 → 20분
실제 효과
Before
– 수작업으로 VLOOKUP, 눈으로 확인
– 마감 시간: 3시간
– 실수 발생 위험
After
– Power Query Refresh 한 번
– 마감 시간: 20분
– 정확도 100%
– 다른 분석에도 재사용
마치며
이 글에서 소개한 테이블 비교 로직은 단순한 Excel 트릭이 아닙니다.
회계 실무의 반복 작업을 시스템화하고,
AI 시대에 생존하는 회계 실무자의 모습을 보여주는 실전 사례입니다.
도메인 지식(회계) + 기술(Power Query) + AI 협업 = 대체 불가능한 가치
여러분도 지금 당장 적용해보세요. 다음 월말 마감이 기다려질 겁니다.
Tags: #회계실무 #PowerQuery #Excel자동화 #데이터분석 #변경추적 #VarianceAnalysis #AI시대생존전략
카테고리: 회계, 데이터 분석, 자동화
© 2025 B.J.T. – Boundless Journey of Thought
https://www.boundlessjourneyofthought.com/
함께 읽으면 좋은 글
Leave a Reply