Beancount beschikt over een krachtige, SQL-achtige Query Language (BQL) waarmee u uw financiële gegevens nauwkeurig kunt selecteren, filteren en analyseren. Of u nu een snel rapport wilt genereren, een boeking wilt debuggen of complexe analyses wilt uitvoeren, het beheersen van BQL is essentieel om het volledige potentieel van uw plaintext-boekhouding te benutten. Deze handleiding leidt u door de structuur, functies en best practices. 🔍

Querystructuur en uitvoering
De kern van BQL is de vertrouwde, op SQL geïnspireerde syntax. Queries worden uitgevoerd met het bea query commandoregelprogramma, dat uw grootboekbestand verwerkt en de resultaten direct in uw terminal weergeeft. Elke query in deze handleiding is uitgevoerd met Beancount 3.2.3 en beanquery 0.2.0.
Basisqueryformaat
Een BQL-query bestaat uit drie hoofdcomponenten: SELECT, FROM en WHERE.
SELECT <target1>, <target2>, ...
FROM <entry-filter-expression>
WHERE <posting-filter-expression>;SELECT: Specificeert welke gegevenskolommen u wilt ophalen.FROM: Filtert volledige transacties voordat ze worden verwerkt.WHERE: Filtert de individuele boekingregels nadat de transactie is geselecteerd.
Tweeledig filtersysteem
Het verschil tussen de FROM- en WHERE-clausules begrijpen is cruciaal voor het schrijven van nauwkeurige queries. BQL gebruikt een tweeledig filterproces.
-
Transactieniveau (
FROM) Deze clausule werkt op volledige transacties. Als een transactie voldoet aan deFROM-voorwaarde, wordt de volledige transactie (inclusief alle boekingen) doorgegeven aan de volgende fase. Dit is de primaire manier om gegevens te filteren, omdat het de integriteit van het dubbel boekhouden behoudt. Bijvoorbeeld, filteren opFROM year = 2024selecteert alle transacties die in 2024 plaatsvonden. -
Boekingniveau (
WHERE) Deze clausule filtert de individuele boekingen binnen de transacties die door deFROM-clausule zijn geselecteerd. Dit is handig voor presentatie en voor het focussen op specifieke delen van een transactie. Houd er echter rekening mee dat filteren op dit niveau de "integriteit" van een transactie in de uitvoer kan "verbreken", omdat u mogelijk slechts één kant van een boeking ziet. U kunt bijvoorbeeld alle boekingen naar uwExpenses:Groceries-rekening selecteren.
Concreet: PRINT FROM year = 2024 retourneert volledige transacties (beide zijden van elke boeking), terwijl SELECT date, narration, account, position FROM year = 2024 WHERE account ~ "Assets:Broker" één rij per overeenkomende boeking retourneert. Op een grootboek met twee aankopen bij de broker retourneert de eerste de volledige boekingen en de tweede precies de twee brokerregels.
Datamodel
Om uw gegevens effectief te kunnen bevragen, moet u begrijpen hoe Beancount gegevens structureert. Een grootboek is een lijst van richtlijnen, maar BQL richt zich voornamelijk op Transaction-boekingen.
Transactiestructuur
Elke Transaction is een container met attributen op het hoogste niveau en een lijst van Posting-objecten.
Transaction
├── date
├── flag
├── payee
├── narration
├── tags
├── links
└── Postings[]
├── account
├── units
├── cost
├── price
└── metadataBeschikbare kolomtypen
U kunt elk attribuut van de transactie of de boekingen selecteren met SELECT.
-
Transactie-attributen Deze kolommen zijn hetzelfde voor elke boeking binnen een enkele transactie.
SELECT date, -- The date of the transaction (datetime.date) year, -- The year of the transaction (int) month, -- The month of the transaction (int) day, -- The day of the transaction (int) flag, -- The transaction flag, e.g., "*" or "!" (str) payee, -- The payee (str) narration, -- The description or memo (str) tags, -- A set of tags, e.g., #trip-2024 (set[str]) links -- A set of links, e.g., ^expense-report (set[str]) -
Boeking-attributen Deze kolommen zijn specifiek voor elke individuele boekingregel.
SELECT account, -- The account name (str) position, -- The full amount, including units and cost (Position) units(position), -- The number and currency of the posting (Amount) cost(position), -- The cost basis of the posting (Amount) price, -- The price used in the posting (Amount) weight, -- The position converted to its cost basis (Amount) balance -- The running total of units in the account (Inventory)unitsencostzijn functies diepositionals argument nemen.price,weightenbalancezijn gewone kolommen.
Queryfuncties
BQL bevat een reeks functies voor aggregatie en datatransformatie, vergelijkbaar met SQL.
Aggregatiefuncties
Aggregatiefuncties vatten gegevens samen over meerdere rijen. In combinatie met GROUP BY bieden ze gegroepeerde overzichten.
-- Count the number of postings
SELECT COUNT(*)
-- Sum all postings into one Inventory; currencies and lots are kept, not converted
SELECT SUM(position)
-- one row, e.g. (-2300.00 USD, 10 HOOL {150.00 USD, 2024-09-05}, 5 HOOL {160.00 USD, 2024-11-02})
-- Total one account in a single currency explicitly (positions without a price keep their currency)
SELECT SUM(CONVERT(position, 'USD')) WHERE account ~ "Assets:Checking"
-- one row, e.g. (2580.00 USD)
-- Find the date of the first and last transaction
SELECT FIRST(date), LAST(date)
-- Find the minimum and maximum position values
SELECT MIN(position), MAX(position)
-- Group by account to get a sum for each
SELECT account, SUM(position) GROUP BY accountPositie-/inventarisfuncties
De position-kolom is een samengesteld object. Deze functies stellen u in staat specifieke delen ervan te extraheren of de marktwaarde ervan te berekenen.
-- Extract just the number and currency from a position
SELECT UNITS(position)
-- Show the total cost of a position
SELECT COST(position)
-- Show each posting at its cost value (a column; there is no WEIGHT() function)
SELECT account, weight WHERE account ~ "Assets:Investments"
-- Calculate the market value using the latest price data
-- (needs a price directive for the holding; otherwise the position is returned unchanged)
SELECT VALUE(position)U kunt deze combineren voor krachtige rapporten. Bijvoorbeeld om de totale kostprijs en actuele marktwaarde van uw beleggingsportefeuille te zien. De marktwaarde vereist een price-richtlijn voor elke positie (bijvoorbeeld 2024-12-01 price HOOL 175.00 USD). Beide aggregaten retourneren een Inventory per rekening, zodat elke valuta afzonderlijk wordt weergegeven.
SELECT
account,
COST(SUM(position)) AS total_cost,
VALUE(SUM(position)) AS market_value
FROM
account ~ "Assets:Investments"
GROUP BY
account
-- one row per account, e.g. Assets:Broker:HOOL | (2300.00 USD) | (2625.00 USD)Geavanceerde functies
Naast basis-SELECT-instructies biedt BQL gespecialiseerde commando's voor veelvoorkomende financiële rapporten.
Balansrapporten
De BALANCES-instructie genereert een balans of winst-en-verliesrekening voor een specifieke periode.
-- Generate a simple balance sheet as of the start of 2024
BALANCES FROM close ON 2024-01-01
WHERE account ~ "^Assets|^Liabilities"
-- Generate an income statement for the 2024 fiscal year
BALANCES FROM
OPEN ON 2024-01-01
CLOSE ON 2024-12-31
WHERE account ~ "^Income|^Expenses"Journaalrapporten
De JOURNAL-instructie toont de gedetailleerde activiteit voor één of meerdere rekeningen, vergelijkbaar met een traditioneel grootboekoverzicht.
-- Show all activity in your checking account at its original cost
JOURNAL "Assets:Checking" AT COST
-- Show all 401k transactions, displaying only the units (shares)
JOURNAL "Assets:.*:401k" AT UNITSPrintbewerkingen
De PRINT-instructie is een debugtool die volledige, overeenkomende transacties in hun oorspronkelijke Beancount-bestandsformaat uitvoert. Het accepteert alleen een ingangsfilter. Een WHERE-clausule is hier een syntaxfout. Om de uitvoer te beperken tot één kant van elke boeking, gebruikt u SELECT met een boekingsfilter. Dit retourneert één rij per overeenkomende boeking.
-- Print all 2024 transactions in full (every posting of each matching entry)
PRINT FROM year = 2024
-- Show only the investment postings of 2024 transactions
SELECT date, narration, account, position
FROM year = 2024
WHERE account ~ "Assets:Investments"
-- Find a transaction by its unique ID (generated by some tools)
-- Returns the matching entry, or no rows when nothing carries that ID
PRINT FROM id = "8e7c47250d040ae2b85de580dd4f5c2a"Filterexpressies
U kunt geavanceerde filters bouwen met logische operatoren (AND, OR), reguliere expressies (~) en vergelijkingen.
Stringliteral gebruiken enkele aanhalingstekens. Dubbele aanhalingstekens begrenzen de reguliere expressie na ~.
-- Find all travel expenses from the second half of 2024
-- SELECT * returns date, flag, payee, narration and position per matching posting
SELECT * FROM
year = 2024 AND month >= 6
WHERE account ~ "Expenses:Travel"
-- Find all transactions related to a vacation or business
SELECT * FROM
'vacation-2024' IN tags OR
'business-trip' IN linksPrestatieoverwegingen ⚙️
bea query is ontworpen voor efficiëntie, maar inzicht in de operationele stroom kan u helpen snellere queries te schrijven op grote grootboeken.
- Gegevens laden: Beancount parseert eerst uw volledige grootboekbestand en sorteert alle transacties chronologisch. De volledige dataset wordt in het geheugen bewaard.
- Queryoptimalisatie: De query-engine past filters in een specifieke volgorde toe voor maximale efficiëntie:
FROM(transacties) ->WHERE(boekingen) -> Aggregaties. Filteren opFROM-niveau is het snelst omdat het de dataset vroeg reduceert. - Geheugengebruik: Alle bewerkingen vinden in het geheugen plaats.
Position-objecten enInventory-aggregaties zijn geoptimaliseerd, maar zeer grote resultaatsets kunnen aanzienlijk RAM-geheugen verbruiken. BQL gebruikt geen tijdelijke opslag op schijf.
Best practices
Volg deze tips om schone, effectieve en onderhoudbare queries te schrijven.
-
Query-organisatie Formatteer uw queries voor leesbaarheid, vooral complexe. Gebruik regeleinden en inspringing om componenten te scheiden.
-- A clean, readable query for all 2024 expenses SELECT date, account, position FROM year = 2024 WHERE account ~ "Expenses" ORDER BY date DESC; -
Debuggen Als een query niet werkt zoals verwacht, voer dan eerst een klein voorbeeld uit met
LIMIT. Om een filter te testen, gebruikt uSELECT DISTINCTom te zien welke unieke waarden het matcht.-- Preview the first rows while iterating SELECT date, account, position LIMIT 5; -- Test which accounts match a regular expression SELECT DISTINCT account WHERE account ~ "^Assets:.*"; -
Balanscontroles U kunt BQL gebruiken om de
balance-controles in uw grootboek dubbel te controleren. Deze query moet het exacte bedrag retourneren dat is opgegeven in uw laatste balanscontrole voor die rekening.-- Verify the final balance of your checking account SELECT account, sum(position) FROM close ON 2025-01-01 -- Use the date from your balance directive WHERE account = "Assets:Checking";