Zum Hauptinhalt springen

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.

  1. Transaktionsebene (FROM) Diese Klausel wirkt sich auf ganze Transaktionen aus. Wenn eine Transaktion die FROM-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 Filtern FROM year = 2024 alle Transaktionen aus, die im Jahr 2024 stattgefunden haben.

  2. Buchungsebene (WHERE) Diese Klausel filtert die einzelnen Buchungen innerhalb der Transaktionen, die durch die FROM-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 Konto Expenses:Groceries auswä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.

  1. 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])
  2. 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.

  1. Daten laden: Beancount analysiert zunächst Ihre gesamte Journaldatei und sortiert alle Transaktionen chronologisch. Dieser gesamte Datensatz wird im Speicher gehalten.
  2. Abfrageoptimierung: Die Abfrage-Engine wendet Filter in einer bestimmten Reihenfolge an, um maximale Effizienz zu erzielen: FROM (Transaktionen) -> WHERE (Buchungen) -> Aggregationen. Das Filtern auf der FROM-Ebene ist am schnellsten, da es den Datensatz frühzeitig reduziert.
  3. Speichernutzung: Alle Operationen finden im Speicher statt. Position-Objekte und Inventory-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.

  1. 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;
  2. Debugging Wenn eine Abfrage nicht wie erwartet funktioniert, verwenden Sie EXPLAIN, um zu sehen, wie Beancount sie analysiert. Um einen Filter zu testen, verwenden Sie SELECT 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:.*";
  3. 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";