Beancount 쿼리 언어 - SQL과 유사한 재무 쿼리
Beancount는 강력한 SQL과 유사한 쿼리 언어(BQL)를 제공하여 재무 데이터를 정확하게 분할, 분석 및 분석할 수 있습니다. 빠른 보고서를 생성하거나, 항목을 디버깅하거나, 복잡한 분석을 수행하려는 경우 BQL을 마스터하면 일반 텍스트 회계 장부의 잠재력을 최대한 활용할 수 있습니다. 이 가이드에서는 구조, 기능 및 모범 사례를 안내합니다. 🔍
쿼리 구조 및 실행
BQL의 핵심은 익숙한 SQL에서 영감을 받은 구문입니다. 쿼리는 bean-query
명령줄 도구를 사용하여 실행되며, 이 도구는 장부 파일을 처리하고 결과를 터미널에 직접 반환합니다.
기본 쿼리 형식
BQL 쿼리는 세 가지 주요 절로 구성됩니다. SELECT, FROM 및 WHERE.
SELECT <target1>, <target2>, ...
FROM <entry-filter-expression>
WHERE <posting-filter-expression>;
SELECT
: 검색할 데이터 열을 지정합니다.FROM
: 전체 트랜잭션을 처리 하기 전에 필터링합니다.WHERE
: 트랜잭션이 선택된 후에 개별 포스팅 라인을 필터링합니다.
2단계 필터링 시스템
FROM
및 WHERE
절의 차이점을 이해하는 것은 정확한 쿼리를 작성하는 데 매우 중요합니다. BQL은 2단계 필터링 프로세스를 사용합니다.
-
트랜잭션 수준 (
FROM
) 이 절은 전체 트랜잭션에 작용합니다. 트랜잭션이FROM
조건을 충족하면 전체 트랜잭션 (모든 포스팅 포함)이 다음 단계로 전달됩니다. 이것은 이중 장부 회계 시스템의 무결성을 유지하므로 데이터를 필터링하는 주요 방법입니다. 예를 들어,FROM year = 2024
필터링은 2024년에 발생한 모든 트랜잭션을 선택합니다. -
포스팅 수준 (
WHERE
) 이 절은FROM
절에서 선택한 트랜잭션 내의 개별 포스팅을 필터링합니다. 이는 프레젠테이션 및 트랜잭션의 특정 레그에 집중하는 데 유용합니다. 그러나 이 수준에서 필터링하면 항목의 한쪽 면만 볼 수 있으므로 출력에서 트랜잭션의 무결성을 "깨뜨릴" 수 있습니다. 예를 들어,Expenses:Groceries
계정으로의 모든 포스팅을 선택할 수 있습니다.
데이터 모델
데이터를 효과적으로 쿼리하려면 Beancount가 데이터를 구성하는 방식을 이해해야 합니다. 장부는 지시문의 목록이지만 BQL은 주로 Transaction
항목에 중점을 둡니다.
트랜잭션 구조
각 Transaction
은 최상위 속성 및 Posting
객체 목록이 있는 컨테이너입니다.
Transaction
├── date
├── flag
├── payee
├── narration
├── tags
├── links
└── Postings[]
├── account
├── units
├── cost
├── price
└── metadata
사용 가능한 열 유형
트랜잭션 또는 해당 포스팅의 모든 속성을 SELECT
할 수 있습니다.
-
트랜잭션 속성 이러한 열은 단일 트랜잭션 내의 모든 포스팅에 대해 동일합니다.
SELECT
date, -- 트랜잭션 날짜 (datetime.date)
year, -- 트랜잭션 연도 (int)
month, -- 트랜잭션 월 (int)
day, -- 트랜잭션 일 (int)
flag, -- 트랜잭션 플래그, 예: "*" 또는 "!" (str)
payee, -- 수취인 (str)
narration, -- 설명 또는 메모 (str)
tags, -- 태그 집합, 예: #trip-2024 (set[str])
links -- 링크 집합, 예: ^expense-report (set[str]) -
포스팅 속성 이러한 열은 각 개별 포스팅 라인에 특정합니다.
SELECT
account, -- 계정 이름 (str)
position, -- 단위 및 비용을 포함한 전체 금액 (Position)
units, -- 포스팅의 숫자 및 통화 (Amount)
cost, -- 포스팅의 원가 기준 (Cost)
price, -- 포스팅에 사용된 가격 (Amount)
weight, -- 원가 기준으로 변환된 포지션 (Amount)
balance -- 계정의 단위 누계 (Inventory)
쿼리 함수
BQL에는 SQL과 마찬가지로 집계 및 데이터 변환을 위한 함수 모음이 포함되어 있습니다.
집계 함수
집계 함수는 여러 행에 걸쳐 데이터를 요약합니다. GROUP BY
와 함께 사용하면 그룹화된 요약을 제공합니다.
-- 포스팅 수 계산
SELECT COUNT(*)
-- 모든 포스팅 값 합산 (일반 통화로 변환)
SELECT SUM(position)
-- 첫 번째 및 마지막 트랜잭션 날짜 찾기
SELECT FIRST(date), LAST(date)
-- 최소 및 최대 포지션 값 찾기
SELECT MIN(position), MAX(position)
-- 각 계정의 합계를 구하기 위해 계정별로 그룹화
SELECT account, SUM(position) GROUP BY account
포지션/인벤토리 함수
position
열은 복합 객체입니다. 이러한 함수를 사용하면 특정 부분을 추출하거나 시장 가치를 계산할 수 있습니다.
-- 포지션에서 숫자 및 통화만 추출
SELECT UNITS(position)
-- 포지션의 총 비용 표시
SELECT COST(position)
-- 원가 기준으로 변환된 포지션 표시 (투자에 유용)
SELECT WEIGHT(position)
-- 최신 가격 데이터를 사용하여 시장 가치 계산
SELECT VALUE(position)
이러한 기능을 결합하여 강력한 보고서를 만들 수 있습니다. 예를 들어, 투자 포트폴리오의 총 비용 및 현재 시장 가치를 보려면 다음을 수행 하십시오.
SELECT
account,
COST(SUM(position)) AS total_cost,
VALUE(SUM(position)) AS market_value
FROM
account ~ "Assets:Investments"
GROUP BY
account
고급 기능
기본 SELECT
문 외에도 BQL은 일반적인 재무 보고서에 대한 특수 명령을 제공합니다.
잔액 보고서
BALANCES
문은 특정 기간에 대한 대차 대조표 또는 손익 계산서를 생성합니다.
-- 2024년 초 현재의 간단한 대차 대조표 생성
BALANCES FROM close ON 2024-01-01
WHERE account ~ "^Assets|^Liabilities"
-- 2024 회계 연도에 대한 손익 계산서 생성
BALANCES FROM
OPEN ON 2024-01-01
CLOSE ON 2024-12-31
WHERE account ~ "^Income|^Expenses"
저널 보고서
JOURNAL
문은 하나 이상의 계정에 대한 자세한 활동을 표시하며, 기존 장부 보기와 유사합니다.
-- 원래 비용으로 확인 계정의 모든 활동 표시
JOURNAL "Assets:Checking" AT COST
-- 단위 (주식) 만 표시하는 모든 401k 트랜잭션 표시
JOURNAL "Assets:.*:401k" AT UNITS
인쇄 작업
PRINT
문은 원래 Beancount 파일 형식으로 일치하는 전체 트랜잭션을 출력하는 디버깅 도구입니다.
-- 2024년의 모든 투자 관련 트랜잭션 인쇄
PRINT FROM year = 2024
WHERE account ~ "Assets:Investments"
-- 일부 도구에서 생성한 고유 ID로 트랜잭션 찾기
PRINT FROM id = "8e7c47250d040ae2b85de580dd4f5c2a"
필터링 표현식
논리 연산자(AND
, OR
), 정규 표현식(~
) 및 비교를 사용하여 정교한 필터를 만들 수 있습니다.
-- 2024년 하반기의 모든 출장비 찾기
SELECT * FROM
year = 2024 AND month >= 6
WHERE account ~ "Expenses:Travel"
-- 휴가 또는 비즈니스와 관련된 모든 트랜잭션 찾기
SELECT * FROM
"vacation-2024" IN tags OR
"business-trip" IN links
성능 고려 사항 ⚙️
bean-query
는 효율성을 위해 설계되었지만 작동 흐름을 이해하면 대규모 장부에서 더 빠른 쿼리를 작성하는 데 도움이 될 수 있습니다.
- 데이터 로드: Beancount는 먼저 전체 장부 파일을 구문 분석하고 모든 트랜잭션을 연대순으로 정렬합니다. 이 전체 데이터 세트는 메모리에 보관됩니다.
- 쿼리 최적화: 쿼리 엔진은 최대 효율성을 위해 특정 순서로 필터를 적용합니다.
FROM
(트랜잭션) ->WHERE
(포스팅) -> 집계.FROM
수준에서 필터링하는 것이 가장 빠릅니다. - 메모리 사용량: 모든 작업은 메모리 내에서 수행됩니다.
Position
객체 및Inventory
집계는 최적화되어 있지만 매우 큰 결과 집합은 상당한 RAM을 소비할 수 있습니다. BQL은 디스크 기반 임시 스토리지를 사용하지 않습니다.
모범 사례
다음 팁에 따라 깨끗하고 효과적이며 유지 관리 가능한 쿼리를 작성하십시오.
-
쿼리 구성 특히 복잡한 쿼리의 경우 가독성을 위해 쿼리 형식을 지정하십시오. 줄 바꿈 및 들여 쓰기를 사용하여 절을 구분하십시오.
-- 모든 2024년 비용에 대한 깨끗하고 읽기 쉬운 쿼리
SELECT
date,
account,
position
FROM
year = 2024
WHERE
account ~ "Expenses"
ORDER BY
date DESC; -
디버깅 쿼리가 예상대로 작동하지 않으면
EXPLAIN
을 사용하여 Beancount가 쿼리를 구문 분석하는 방법을 확인하십시오. 필터를 테스트하려면SELECT DISTINCT
를 사용하여 일치하는 고유 값을 확인하십시오.-- 쿼리 계획 보기
EXPLAIN SELECT date, account, position;
-- 정규 표현식과 일치하는 계정 테스트
SELECT DISTINCT account
WHERE account ~ "^Assets:.*"; -
잔액 어설션 BQL을 사용하여 장부의
balance
어설션을 다시 확인할 수 있습니다. 이 쿼리는 해당 계정에 대한 마지막 잔액 확인에 지정된 정확한 금액을 반환해야 합니다.-- 확인 계정의 최종 잔액 확인
SELECT account, sum(position)
FROM close ON 2025-01-01 -- 잔액 지시문의 날짜 사용
WHERE account = "Assets:Checking";