Skip to content

Commit 0f7bda7

Browse files
authored
Add SQL example for category mapping to account balance (#170)
1 parent e24033e commit 0f7bda7

1 file changed

Lines changed: 142 additions & 1 deletion

File tree

README.md

Lines changed: 142 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ To estimate taxable interest for a given year[^1]:
209209
-- @interest_payee_name (optional, defaults to Interest)
210210
--
211211
-- Example with only required params:
212-
-- sqlite3 -header -box path/to/db.sqlite3 \
212+
-- sqlite3 -header -box path/to/db.sqlite \
213213
-- -cmd '.parameter init' \
214214
-- -cmd ".parameter set @tax_rate 0.25" \
215215
-- -cmd ".parameter set @year 2025" \
@@ -294,4 +294,145 @@ ORDER BY plan_name, plan_id
294294
;
295295
```
296296

297+
To compare assigned category values to a given account's balance:
298+
299+
```sql
300+
-- Parameters expected by this query:
301+
-- @account_name_like (required, the account name to match against)
302+
-- @plan_id (optional, defaults to output for all matching plans)
303+
-- @include_category_groups
304+
-- (optional, comma-separated category-group names to include;
305+
-- exclusive with @exclude_category_groups)
306+
-- @exclude_category_groups
307+
-- (optional, comma-separated category-group names to exclude;
308+
-- exclusive with @include_category_groups)
309+
--
310+
-- Example:
311+
-- sqlite -header -box path/to/db.sqlite \
312+
-- -cmd '.parameter init' \
313+
-- -cmd ".parameter set @account_name_like %Savings%" \
314+
-- -cmd ".parameter set @include_category_groups 'Home,Food'" \
315+
-- < query.sql
316+
WITH params AS (
317+
SELECT
318+
TRIM(COALESCE(@account_name_like, '')) AS account_name_like
319+
, TRIM(COALESCE(@include_category_groups, ''))
320+
AS include_category_groups
321+
, TRIM(COALESCE(@exclude_category_groups, ''))
322+
AS exclude_category_groups
323+
)
324+
325+
, validation AS (
326+
SELECT 'Set @account_name_like' AS error FROM params AS p
327+
WHERE p.account_name_like = ''
328+
UNION ALL
329+
SELECT
330+
'Set only one of @include_category_groups'
331+
|| ' or @exclude_category_groups' AS error
332+
FROM params AS p
333+
WHERE p.include_category_groups != '' AND p.exclude_category_groups != ''
334+
)
335+
336+
SELECT v.error AS error_message FROM validation AS v
337+
WHERE v.error IS NOT NULL
338+
;
339+
340+
WITH params AS (
341+
SELECT
342+
TRIM(COALESCE(@account_name_like, '')) AS account_name_like
343+
, TRIM(COALESCE(@include_category_groups, ''))
344+
AS include_category_groups
345+
, TRIM(COALESCE(@exclude_category_groups, ''))
346+
AS exclude_category_groups
347+
)
348+
349+
, validation AS (
350+
SELECT
351+
p.account_name_like
352+
, p.include_category_groups
353+
, p.exclude_category_groups
354+
FROM params AS p
355+
)
356+
357+
, validation_errors AS (
358+
SELECT 'Set @account_name_like' AS error FROM validation AS v
359+
WHERE v.account_name_like = ''
360+
UNION ALL
361+
SELECT
362+
'Set only one of @include_category_groups'
363+
|| ' or @exclude_category_groups' AS error
364+
FROM validation AS v
365+
WHERE v.include_category_groups != '' AND v.exclude_category_groups != ''
366+
)
367+
368+
, valid_params AS (
369+
SELECT
370+
v.account_name_like
371+
, v.include_category_groups
372+
, v.exclude_category_groups
373+
FROM validation AS v
374+
WHERE NOT EXISTS (SELECT 1 FROM validation_errors)
375+
)
376+
377+
, matched_accounts AS (
378+
SELECT
379+
p.id AS plan_id
380+
, p.name AS plan_name
381+
, a.name AS account_name
382+
, a.cleared_balance / 1000.0 AS account_amount
383+
FROM plans AS p
384+
INNER JOIN accounts AS a ON p.id = a.plan_id
385+
CROSS JOIN valid_params AS v
386+
WHERE
387+
TRUE
388+
AND NOT a.deleted
389+
AND a.name LIKE v.account_name_like
390+
AND (COALESCE(@plan_id, '') = '' OR p.id = @plan_id)
391+
)
392+
393+
, category_totals AS (
394+
SELECT
395+
c.plan_id
396+
, COALESCE(SUM(c.balance), 0) / 1000.0 AS total
397+
FROM categories AS c CROSS JOIN valid_params AS v
398+
WHERE
399+
TRUE
400+
AND NOT c.deleted
401+
AND c.category_group_name != 'Credit Card Payments'
402+
AND c.category_group_name != 'Internal Master Category'
403+
AND (
404+
v.include_category_groups = ''
405+
OR INSTR(
406+
','
407+
|| LOWER(REPLACE(v.include_category_groups, ', ', ','))
408+
|| ','
409+
, ',' || LOWER(c.category_group_name) || ','
410+
)
411+
> 0
412+
)
413+
AND (
414+
v.exclude_category_groups = ''
415+
OR INSTR(
416+
','
417+
|| LOWER(REPLACE(v.exclude_category_groups, ', ', ','))
418+
|| ','
419+
, ',' || LOWER(c.category_group_name) || ','
420+
)
421+
= 0
422+
)
423+
AND (COALESCE(@plan_id, '') = '' OR c.plan_id = @plan_id)
424+
GROUP BY c.plan_id
425+
)
426+
427+
SELECT
428+
ma.plan_name AS "plan"
429+
, ma.account_name AS account
430+
, ROUND(COALESCE(ct.total, 0), 2) AS total
431+
, ROUND(ma.account_amount - COALESCE(ct.total, 0), 2) AS excess
432+
FROM matched_accounts AS ma
433+
LEFT JOIN category_totals AS ct ON ma.plan_id = ct.plan_id
434+
ORDER BY "plan", account
435+
;
436+
```
437+
297438
[^1]: This query is a rough estimate based on YNAB data and optional user inputs. It is not financial advice, tax advice, or a substitute for Forms 1099-INT, brokerage statements, bank records, or guidance from a qualified professional.

0 commit comments

Comments
 (0)