은행 CSV 내보내기 파일은 늘 비슷한 방식으로 까다롭습니다. 그 목록을 알면 헷갈리는 파일도 5분이면 끝나는 일이 됩니다. 아래 문제는 모두 은행이 정한 서식일 뿐, 파일이 손상된 것이 아닙니다.
- 머리글 앞의 안내 행. 계좌 이름, 은행 코드(sort code), 조회 기간, 그리고 실제 머리글 앞의 빈 줄이 있습니다. 파일을 읽는 파서는 이 가운데 첫 줄을 열 이름으로 취급합니다.
- 금액이 두 열로 나뉜 경우. 부호가 있는 금액 한 열 대신
Debit과Credit두 열이 있거나, 부호가 있어도 부호 규칙이 예상과 반대입니다. - 모호한 날짜.
03/04/2026은 영국에서는 4월 3일, 미국에서는 3월 4일이며, 파일에는 어느 쪽인지 적혀 있지 않습니다. - 다섯 가지 정보가 한꺼번에 들어 있는 설명 열: 가맹점, 위치, 카드 번호, 참조 번호, 은행 고유의 거래 유형입니다.
- 텍스트로 된 금액. 천 단위 구분 기호, 통화 기호,
(45.00)처럼 괄호로 쓴 음수가 있습니다.
이 다섯 가지를 고치면 파일은 평범한 데이터가 됩니다.
먼저 파일의 모양을 확인합니다
무엇보다 먼저 파일을 열어 처음 열 줄을 봅니다.
head -n 12 statement.csv
안내 행이 몇 줄인지 세고, 실제 머리글이 어느 줄인지 확인합니다. 그런 다음 건너뜁니다.
tail -n +5 statement.csv > clean.csv
스프레드시트에서 연다면 다른 작업보다 먼저 그 행들을 삭제하세요. 그대로 둔 채 정렬하거나 필터링하면 계좌 요약이 거래 내역 한가운데로 들어옵니다. 찾기 어렵고 합계에 섞여 들어가기 쉽습니다.
함정은 날짜입니다
이 오류는 눈에 띄게 망가지는 대신 틀린 답을 만듭니다. 미국식 파서가 영국 명세서를 읽으면 12일까지의 모든 날짜에서 4월 3일을 3월 4일로 조용히 바꾸고, 나머지는 그대로 둡니다. 결과는 완전히 정상으로 보이지만 월별 합계는 모두 틀립니다.
확실한 순서대로 두 가지 방법이 있습니다.
12보다 큰 일을 찾습니다. 날짜 열에서 25/12/2026 같은 값을 찾습니다. 첫 번째 숫자가 12를 넘으면 일이 먼저인 형식입니다. 10초면 되고 확실합니다.
기억하는 거래와 대조합니다. 기억으로 날짜를 댈 수 있는 거래가 하나라도 있으면 순서가 바로 확인됩니다.
그런 다음 도구가 추측하게 두지 말고 명시적으로 변환합니다.
duckdb -c "SELECT strptime(\"Transaction Date\", '%d/%m/%Y') d, * FROM read_csv('clean.csv', all_varchar=true)"
중요한 쪽은 all_varchar=true입니다. 읽는 쪽이 자료형을 아예 추론하지 않으므로 모든 변환을 직접 정하게 됩니다. 참조 번호와 계좌 숫자가 부동소수점 수로 읽히는 것도 막아 줍니다.
금액을 하나로 정리합니다
목표는 부호가 있는 숫자 열 하나이며, 변환할 원본 형태는 세 가지입니다.
Debit과 Credit이 따로 있는 경우. 출금을 음수로 해서 합칩니다.
COALESCE(-TRY_CAST(replace("Debit", ',', '') AS DOUBLE), TRY_CAST(replace("Credit", ',', '') AS DOUBLE), 0)
구분 기호나 기호가 섞인 텍스트. 변환하기 전에 숫자, 마이너스, 소수점이 아닌 것을 모두 제거합니다. £1,234.56과 1 234,56 모두 이 처리가 필요하며, 뒤쪽은 소수점 쉼표까지 처리해야 합니다.
회계식 음수. (45.00)은 −45.00을 뜻합니다. 기본 설정으로 이를 올바르게 변환하는 것은 없으므로 먼저 괄호를 바꿉니다.
합계를 믿기 전에 변환을 검증하세요. NULL이 아닌 금액의 수가 거래 행의 수와 같아야 합니다. TRY_CAST가 실패하면 조용히 NULL이 되고, SUM 안의 NULL은 그냥 빠집니다. 이렇게 해서 합계가 눈에 띄게 망가지는 대신 그럴듯하게 틀리게 됩니다.
설명 열을 나눕니다
쓸모 있는 정보는 설명 열에 숨어 있고, 하나의 문자열로 들어옵니다.
CARD PAYMENT TO TESCO STORES 3421 ON 02-04-2026 GBP 43.19
완전한 파서가 필요한 경우는 드뭅니다. 두 가지 작업이면 대부분 충분합니다.
가맹점 열. 관심 있는 이름의 목록과 비교해서 만듭니다. CASE WHEN description LIKE '%TESCO%' THEN 'Tesco' 같은 절 스무 개면 개인 명세서의 대부분을 분류할 수 있고, 나머지 소수는 자동화할 가치가 없습니다.
거래 유형 열. 앞부분 단어로 만듭니다. CARD PAYMENT, DIRECT DEBIT, FASTER PAYMENT, ATM 등입니다. 같은 내보내기 안에서는 은행의 표기가 일관되며, 유형별로 묶는 편이 가맹점별로 묶는 것보다 더 많은 것을 알려 주는 경우가 많습니다.
시도하지 말아야 할 것은 설명 안에서 믿을 만한 금액이나 날짜를 뽑아내는 일입니다. 둘 다 이미 열로 있고, 텍스트에 들어 있는 사본은 서식이 다르며 때로는 서로 맞지 않습니다.
그다음 진짜 질문을 던집니다
파일에 날짜, 부호가 있는 금액, 가맹점이 갖춰지면 질문은 한 줄씩이면 됩니다.
SELECT strftime(d, '%Y-%m') month, sum(amount) FROM tx GROUP BY month ORDER BY month
SELECT merchant, count(*) n, sum(amount) FROM tx WHERE amount < 0 GROUP BY merchant ORDER BY sum(amount) LIMIT 20
SELECT * FROM tx WHERE amount < -100 ORDER BY amount
월별 순수입, 가맹점별 가장 큰 지출, 100이 넘는 모든 거래입니다. 명세서를 여는 이유의 대부분은 이 세 가지로 답이 나옵니다.
SQL과 시각적 필터 편집기 모두 파일이 있는 자리에서 그대로 실행됩니다. 어디에도 올리고 싶지 않은 은행 내보내기 파일일 때는 바로 이 점이 중요합니다. 차트도 같은 쿼리에서 만들어지므로 월별 합계가 같은 단계에서 막대 차트가 됩니다.
기능마지막 고려 사항은 분명하게 말해 둘 만합니다. 은행 명세서는 대부분의 사람이 다루는 파일 가운데 가장 민감한 축에 속합니다. 모든 가맹점, 모든 위치, 정기 결제, 그리고 흔히 계좌 번호의 일부가 들어 있습니다. 무료 온라인 CSV 뷰어와 「명세서 변환」 사이트는 파일 전체를 아무것도 모르는 서버에 업로드합니다. 이 파일에 한해서는 로컬에서 작동하는 도구를 쓰는 것이 유난이 아니라 당연한 기본값입니다.
다른 사람에게 줄 파일로 손보기
명세서를 연 이유가 세무사, 집주인, 경비 청구처럼 누군가 그 일부를 필요로 해서인 경우가 많습니다. 작업은 빼는 일입니다.
- 필요한 열만 남깁니다. 날짜, 설명, 금액입니다. 잔액과 계좌 숫자를 포함해 나머지는 삭제합니다.
- 실제로 요청받은 기간이나 범주로 필터링합니다.
- 상대가 요구할 만한 범주가 있다면 범주 열을 추가합니다.
- 내보낸 뒤, 내보낸 파일의 합계가 필터 결과의 합계와 일치하는지 확인합니다.
잔액 열은 귀찮다고 남겨 두지 말고 의식적으로 가리는 것이 좋습니다. 거래 내역 자체보다 훨씬 많은 정보가 드러나기 때문입니다.
열 삭제, 기간별 필터링, 계산된 범주 열 추가는 모두 여기서 직접 편집할 수 있습니다. 수식 열은 결과를 CSV에 저장하므로, 넘겨 주는 파일은 받는 쪽이 어떤 도구를 쓰든 제대로 열리는 평범한 CSV입니다.
기능여러 달, 여러 계좌
은행은 한 번에 한 기간씩 내보내므로 1년에 걸친 질문에는 파일이 여러 개 필요합니다. 합치기 전에 할 일이 두 가지 있습니다.
머리글이 일치하는지 확인합니다. 은행은 해마다 내보내기 형식을 바꾸며, 열 위치가 달라진 상태에서 아무 확인 없이 이어 붙이면 그 뒤의 모든 열이 어긋납니다. 먼저 머리글 행을 비교하세요. CSV 파일 병합 가이드에서 이런 변화에도 견디는, 열 이름 기준 병합을 다룹니다.
계좌 열을 추가합니다. 서로 다른 계좌의 파일을 합치기 전에 해야 합니다. 없으면 내 계좌 사이의 이체가 출금으로 한 번, 입금으로 한 번, 두 번 나타나고, 이를 무시한 합계는 모두 이체 금액의 두 배만큼 틀립니다. 출처를 표시한 뒤 내부 이체를 명시적으로 제외하는 것이 의미 있는 가계 합계를 얻는 유일한 방법입니다.