Beancount Query Language - SQL-ähnliche Finanzabfragen
Beancount verfügt über eine leistungsstarke, SQL-ähnliche Abfragesprache (BQL), mit der Sie Ihre Finanzdaten präzise analysieren und aufschlüsseln können. Egal, ob Sie einen schnellen Bericht erstellen, einen Eintrag debuggen oder eine komplexe Analyse durchführen möchten, die Beherrschung von BQL ist der Schlüssel, um das volle Potenzial Ihres Plaintext-Buchhaltungsjournals auszuschöpfen. Dieser Leitfaden führt Sie durch die Struktur, Funktionen und Best Practices. 🔍
Abfragestruktur und Ausführung
Der Kern von BQL ist die vertraute, von SQL inspirierte Syntax. Abfragen werden mit dem Befehlszeilentool bean-query ausgeführt, das Ihre Journaldatei verarbeitet und die Ergebnisse direkt in Ihrem Terminal zurückgibt.
Grundlegendes Abfrageformat
Eine BQL-Abfrage besteht aus drei Hauptklauseln: SELECT, FROM und WHERE.
SELECT <Ziel1>, <Ziel2>, ...
FROM <Eintragsfilterausdruck>
WHERE <Buchungsfilterausdruck>;
SELECT: Gibt an, welche Datenspalten Sie abrufen möchten.FROM: Filtert ganze Transaktionen bevor sie verarbeitet werden.WHERE: Filtert die einzelnen Buchungszeilen nachdem die Transaktion ausgewählt wurde.
Zweistufiges Filtersystem
Das Verständnis des Unterschieds zwischen den Klauseln FROM und WHERE ist entscheidend für das Schreiben genauer Abfragen. BQL verwendet einen zweistufigen Filterprozess.
-
Transaktionsebene (
FROM) Diese Klausel wirkt sich auf ganze Transaktionen aus. Wenn eine Transaktion dieFROM-Bedingung erfüllt, wird die gesamte Transaktion (einschließlich aller ihrer Buchungen) an die nächste Stufe weitergeleitet. Dies ist die primäre Methode zum Filtern von Daten, da sie die Integrität des doppelten Buchführungssystems bewahrt. Beispielsweise wählt das FilternFROM year = 2024alle Transaktionen aus, die im Jahr 2024 stattgefunden haben. -
Buchungsebene (
WHERE) Diese Klausel filtert die einzelnen Buchungen innerhalb der Transaktionen, die durch dieFROM-Klausel ausgewählt wurden. Dies ist nützlich für die Präsentation und um sich auf bestimmte Teile einer Transaktion zu konzentrieren. Beachten Sie jedoch, dass das Filtern auf dieser Ebene die Integrität einer Transaktion in der Ausgabe "brechen" kann, da Sie möglicherweise nur eine Seite eines Eintrags sehen. Beispielsweise können Sie alle Buchungen auf Ihr KontoExpenses:Groceriesauswählen.
Datenmodell
Um Ihre Daten effektiv abzufragen, müssen Sie verstehen, wie Beancount sie strukturiert. Ein Journal ist eine Liste von Direktiven, aber BQL konzentriert sich hauptsächlich auf Transaction-Einträge.
Transaktionsstruktur
Jede Transaction ist ein Container mit Attributen der obersten Ebene und einer Liste von Posting-Objekten.
Transaction
├── date
├── flag
├── payee
├── narration
├── tags
├── links
└── Postings[]
├── account
├── units
├── cost
├── price
└── metadata
Verfügbare Spaltentypen
Sie können jedes der Attribute aus der Transaktion oder ihren Buchungen SELECT auswählen.
-
Transaktionsattribute Diese Spalten sind für jede Buchung innerhalb einer einzelnen Transaktion gleich.
SELECT
date, -- Das Datum der Transaktion (datetime.date)
year, -- Das Jahr der Transaktion (int)
month, -- Der Monat der Transaktion (int)
day, -- Der Tag der Transaktion (int)
flag, -- Das Transaktionskennzeichen, z. B. "*" oder "!" (str)
payee, -- Der Zahlungsempfänger (str)
narration, -- Die Beschreibung oder Notiz (str)
tags, -- Eine Menge von Tags, z. B. #trip-2024 (set[str])
links -- Eine Menge von Links, z. B. ^expense-report (set[str]) -
Buchungsattribute Diese Spalten sind spezifisch für jede einzelne Buchungszeile.
SELECT
account, -- Der Kontoname (str)
position, -- Der vollständige Betrag, einschließlich Einheiten und Kosten (Position)
units, -- Die Anzahl und Währung der Buchung (Amount)
cost, -- Die Kostenbasis der Buchung (Cost)
price, -- Der in der Buchung verwendete Preis (Amount)
weight, -- Die Position, umgerechnet in ihre Kostenbasis (Amount)
balance -- Der fortlaufende Gesamtbetrag der Einheiten auf dem Konto (Inventory)
Abfragefunktionen
BQL enthält eine Reihe von Funktionen zur Aggregation und Datentransformation, ähnlich wie SQL.
Aggregationsfunktionen
Aggregationsfunktionen fassen Daten über mehrere Zeilen zusammen. In Kombination mit GROUP BY bieten sie gruppierte Zusammenfassungen.
-- Zählen der Anzahl der Buchungen
SELECT COUNT(*)
-- Summieren des Wertes aller Buchungen (umgerechnet in eine gemeinsame Währung)
SELECT SUM(position)
-- Ermitteln des Datums der ersten und letzten Transaktion
SELECT FIRST(date), LAST(date)
-- Ermitteln der minimalen und maximalen Positionswerte
SELECT MIN(position), MAX(position)
-- Gruppieren nach Konto, um eine Summe für jedes Konto zu erhalten
SELECT account, SUM(position) GROUP BY account
Positions-/Inventarfunktionen
Die Spalte position ist ein zusammengesetztes Objekt. Mit diesen Funktionen können Sie bestimmte Teile davon extrahieren oder ihren Marktwert berechnen.
-- Extrahieren Sie nur die Anzahl und Währung aus einer Position
SELECT UNITS(position)
-- Anzeigen der Gesamtkosten einer Position
SELECT COST(position)
-- Anzeigen der Position, umgerechnet in ihre Kostenbasis (nützlich für Investitionen)
SELECT WEIGHT(position)
-- Berechnen des Marktwerts anhand der neuesten Preisdaten
SELECT VALUE(position)
Sie können diese für aussagekräftige Berichte kombinieren. Um beispielsweise die Gesamtkosten und den aktuellen Marktwert Ihres Anlageportfolios anzuzeigen:
SELECT
account,
COST(SUM(position)) AS total_cost,
VALUE(SUM(position)) AS market_value
FROM
account ~ "Assets:Investments"
GROUP BY
account
Erweiterte Funktionen
Über grundlegende SELECT-Anweisungen hinaus bietet BQL spezielle Befehle für gängige Finanzberichte.
Saldenberichte
Die BALANCES-Anweisung generiert eine Bilanz oder Gewinn- und Verlustrechnung für einen bestimmten Zeitraum.
-- Generieren einer einfachen Bilanz zum Beginn des Jahres 2024
BALANCES FROM close ON 2024-01-01
WHERE account ~ "^Assets|^Liabilities"
-- Generieren einer Gewinn- und Verlustrechnung für das Geschäftsjahr 2024
BALANCES FROM
OPEN ON 2024-01-01
CLOSE ON 2024-12-31
WHERE account ~ "^Income|^Expenses"
Journalberichte
Die JOURNAL-Anweisung zeigt die detaillierte Aktivität für ein oder mehrere Konten an, ähnlich einer herkömmlichen Journalansicht.
-- Anzeigen aller Aktivitäten auf Ihrem Girokonto zu ihren ursprünglichen Kosten
JOURNAL "Assets:Checking" AT COST
-- Anzeigen aller 401k-Transaktionen, wobei nur die Einheiten (Anteile) angezeigt werden
JOURNAL "Assets:.*:401k" AT UNITS
Druckoperationen
Die PRINT-Anweisung ist ein Debugging-Tool, das vollständige, übereinstimmende Transaktionen in ihrem ursprünglichen Beancount-Dateiformat ausgibt.
-- Drucken aller anlagebezogenen Transaktionen aus dem Jahr 2024
PRINT FROM year = 2024
WHERE account ~ "Assets:Investments"
-- Suchen einer Transaktion anhand ihrer eindeutigen ID (die von einigen Tools generiert wird)
PRINT FROM id = "8e7c47250d040ae2b85de580dd4f5c2a"
Filterausdrücke
Sie können anspruchsvolle Filter mit logischen Operatoren (AND, OR), regulären Ausdrücken (~) und Vergleichen erstellen.
-- Suchen aller Reisekosten aus der zweiten Hälfte des Jahres 2024
SELECT * FROM
year = 2024 AND month >= 6
WHERE account ~ "Expenses:Travel"
-- Suchen aller Transaktionen im Zusammenhang mit einem Urlaub oder einer Geschäftsreise
SELECT * FROM
"vacation-2024" IN tags OR
"business-trip" IN links
Leistungsüberlegungen ⚙️
bean-query ist auf Effizienz ausgelegt, aber das Verständnis des Betriebsablaufs kann Ihnen helfen, schnellere Abfragen auf großen Journalen zu schreiben.
- Daten laden: Beancount analysiert zunächst Ihre gesamte Journaldatei und sortiert alle Transaktionen chronologisch. Dieser gesamte Datensatz wird im Speicher gehalten.
- Abfrageoptimierung: Die Abfrage-Engine wendet Filter in einer bestimmten Reihenfolge an, um maximale Effizienz zu erzielen:
FROM(Transaktionen) ->WHERE(Buchungen) -> Aggregationen. Das Filtern auf derFROM-Ebene ist am schnellsten, da es den Datensatz frühzeitig reduziert. - Speichernutzung: Alle Operationen finden im Speicher statt.
Position-Objekte undInventory-Aggregationen sind optimiert, aber sehr große Ergebnismengen können erheblichen RAM verbrauchen. BQL verwendet keinen plattenbasierten temporären Speicher.
Bewährte Verfahren
Befolgen Sie diese Tipps, um saubere, effektive und wartbare Abfragen zu schreiben.
-
Abfrageorganisation Formatieren Sie Ihre Abfragen zur besseren Lesbarkeit, insbesondere komplexe Abfragen. Verwenden Sie Zeilenumbrüche und Einrückungen, um Klauseln zu trennen.
-- Eine saubere, lesbare Abfrage für alle Ausgaben des Jahres 2024
SELECT
date,
account,
position
FROM
year = 2024
WHERE
account ~ "Expenses"
ORDER BY
date DESC; -
Debugging Wenn eine Abfrage nicht wie erwartet funktioniert, verwenden Sie
EXPLAIN, um zu sehen, wie Beancount sie analysiert. Um einen Filter zu testen, verwenden SieSELECT DISTINCT, um zu sehen, welche eindeutigen Werte er findet.-- Anzeigen des Abfrageplans
EXPLAIN SELECT date, account, position;
-- Testen, welche Konten mit einem regulären Ausdruck übereinstimmen
SELECT DISTINCT account
WHERE account ~ "^Assets:.*"; -
Saldenbestätigungen Sie können BQL verwenden, um die
balance-Bestätigungen in Ihrem Journal zu überprüfen. Diese Abfrage sollte den genauen Betrag zurückgeben, der in Ihrer letzten Saldenprüfung für dieses Konto angegeben wurde.-- Überprüfen des endgültigen Saldos Ihres Girokontos
SELECT account, sum(position)
FROM close ON 2025-01-01 -- Verwenden Sie das Datum aus Ihrer Saldenrichtlinie
WHERE account = "Assets:Checking";