Skip to main content

SQLite Export for YNAB - Export YNAB Data to SQLite

Project description

sqlite-export-for-ynab

pre-commit.ci status codecov

SQLite Export for YNAB - Export YNAB Budget Data to SQLite

What This Does

Export all your YNAB plans to a local SQLite DB. Then you can query your data with any tools compatible with SQLite.

Installation

$ pip install sqlite-export-for-ynab

Usage

CLI

Provision a YNAB Personal Access Token and save it as an environment variable.

$ export YNAB_PERSONAL_ACCESS_TOKEN="..."

Run the tool from the terminal to download your plans:

$ sqlite-export-for-ynab

Running it again will pull only data that changed since the last pull (this is done with Delta Requests). If you want to wipe the DB and pull all data again use the --full-refresh flag.

You can specify the DB path with the following options

  1. The --db flag.
  2. The XDG_DATA_HOME variable (see the XDG Base Directory Specification). In that case the DB is saved in "${XDG_DATA_HOME}"/sqlite-export-for-ynab/db.sqlite.
  3. If neither is set, the DB is saved in ~/.local/share/sqlite-export-for-ynab/db.sqlite.

Library

The library exposes the package sqlite_export_for_ynab and two functions - default_db_path and sync. You can use them as follows:

import asyncio
import os

from sqlite_export_for_ynab import default_db_path
from sqlite_export_for_ynab import sync

db = default_db_path()
token = os.environ["YNAB_PERSONAL_ACCESS_TOKEN"]
full_refresh = False

asyncio.run(sync(token, db, full_refresh))

Relations

The relations are defined in create-relations.sql. They are 1:1 with YNAB's OpenAPI Spec (ex: transactions, accounts, etc) with some additions:

  1. Some objects are pulled out into their own tables so they can be more cleanly modeled in SQLite (ex: subtransactions, loan account periodic values).
  2. Foreign keys are added as needed (ex: plan ID, transaction ID) so data across plans remains separate.
  3. Two new views called flat_transactions and scheduled_flat_transactions. These allow you to query split and non-split transactions easily, without needing to also query subtransactions and scheduled_subtransactions respectively. They also include fields to improve quality of life (ex: amount_major to convert from YNAB's milliunits to major units i.e. dollars) and filter out deleted transactions/subtransactions.

Querying

You can issue queries with typical SQLite tools. sqlite-export-for-ynab deliberately does not implement a SQL REPL.

Sample Queries

To get the top 5 payees by spending per plan, you could do:

WITH
ranked_payees AS (
    SELECT
        pl."name" AS plan_name
        , t.payee_name AS payee
        , SUM(t.amount_major) AS net_spent
        , ROW_NUMBER() OVER (
            PARTITION BY
                pl.id
            ORDER BY
                SUM(t.amount) ASC
        ) AS rnk
    FROM
        flat_transactions AS t
    INNER JOIN plans AS pl
        ON t.plan_id = pl.id
    WHERE
        t.payee_name != 'Starting Balance'
        AND t.transfer_account_id IS NULL
    GROUP BY
        pl.id
        , t.payee_id
)

SELECT
    plan_name
    , payee
    , net_spent
FROM
    ranked_payees
WHERE
    rnk <= 5
ORDER BY
    plan_name ASC
    , net_spent DESC
;

To get duplicate payees, or payees with no transactions:

SELECT DISTINCT
    pl."name" AS "plan"
    , dupes."name" AS payee
FROM (
    SELECT DISTINCT
        p.plan_id
        , p."name"
    FROM payees AS p
    LEFT JOIN flat_transactions AS ft
        ON
            p.plan_id = ft.plan_id
            AND p.id = ft.payee_id
    LEFT JOIN scheduled_flat_transactions AS sft
        ON
            p.plan_id = sft.plan_id
            AND p.id = sft.payee_id
    WHERE
        TRUE
        AND ft.payee_id IS NULL
        AND sft.payee_id IS NULL
        AND p.transfer_account_id IS NULL
        AND p."name" != 'Reconciliation Balance Adjustment'
        AND p."name" != 'Manual Balance Adjustment'
        AND NOT p.deleted

    UNION ALL

    SELECT
        plan_id
        , "name"
    FROM payees
    WHERE NOT deleted
    GROUP BY plan_id, "name"
    HAVING COUNT(*) > 1

) AS dupes
INNER JOIN plans AS pl
    ON dupes.plan_id = pl.id
ORDER BY "plan", payee
;

To count the spend for a category (ex: "Apps") between this month and the next 11 months (inclusive):

SELECT
    plan_id
    , SUM(amount_major) AS amount_major
FROM (
    SELECT
        plan_id
        , amount_major
    FROM flat_transactions
    WHERE
        category_name = 'Apps'
        AND SUBSTR(`date`, 1, 7) = SUBSTR(DATE(), 1, 7)
    UNION ALL
    SELECT
        plan_id
        , amount_major * (
            CASE
                WHEN frequency = 'monthly' THEN 11
                ELSE 1 -- assumes yearly
            END
        ) AS amount_major
    FROM scheduled_flat_transactions
    WHERE
        category_name = 'Apps'
        AND SUBSTR(date_next, 1, 7) < SUBSTR(DATE('now', '+1 year'), 1, 7)
)
;

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sqlite_export_for_ynab-2.0.0.tar.gz (16.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sqlite_export_for_ynab-2.0.0-py2.py3-none-any.whl (16.4 kB view details)

Uploaded Python 2Python 3

File details

Details for the file sqlite_export_for_ynab-2.0.0.tar.gz.

File metadata

  • Download URL: sqlite_export_for_ynab-2.0.0.tar.gz
  • Upload date:
  • Size: 16.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for sqlite_export_for_ynab-2.0.0.tar.gz
Algorithm Hash digest
SHA256 ea22b3e49a8386e770d710df130250c120d1858da3c10d9ec61c31526ab21a88
MD5 e13e908a5b646149732e522d4a2e03b2
BLAKE2b-256 b232d8a306269fc548bd964f3ea0371d6566bcf435d0de81c03db3dc0820f0ba

See more details on using hashes here.

File details

Details for the file sqlite_export_for_ynab-2.0.0-py2.py3-none-any.whl.

File metadata

File hashes

Hashes for sqlite_export_for_ynab-2.0.0-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 3d3ba93d701f251d5e59da30d11a341617330158d0d0a764b9c5cb0f6b8804d4
MD5 63e04802c59e452024961e3723ac0c00
BLAKE2b-256 39c173d55782692a2c6c852e45caeb4f9344f513f1538fb0ba201122c9640070

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page