Adds date-parameterized SQL queries for Income Statement, Expense Detail, Vendor Payment Summary, and General Ledger. These filter TransactionLines by date range instead of using cumulative balances, enabling tax year and other period-specific financial reports.
7.4 KiB
SQL Queries and Reports
Common queries and financial report templates.
Contents
Common Queries
Unpaid Bills by Vendor
SELECT v.Name, b.BillNumber, b.BillDate, b.Amount, b.AmountDue
FROM Bills b
JOIN Vendors v ON b.Vendor = v.id
WHERE b.Status IN ('Open', 'Partial')
ORDER BY b.DueDate
Bills Summary by Vendor
SELECT v.Name as Vendor, COUNT(b.id) as Bills, SUM(b.Amount) as Total, SUM(b.AmountDue) as Due
FROM Bills b
JOIN Vendors v ON b.Vendor = v.id
GROUP BY v.Name
ORDER BY Total DESC
Account Balances (Non-Zero)
SELECT Code, Name, Type, Balance
FROM Accounts
WHERE Balance != 0
ORDER BY Code
Owner Reimbursement Balance
SELECT Balance FROM Accounts WHERE Code = '2203'
Expense Summary by Account
SELECT a.Code, a.Name, a.Balance
FROM Accounts a
WHERE a.Type = 'Expense' AND a.Balance != 0
ORDER BY a.Balance DESC
Transaction History for Account
SELECT t.Date, t.Description, t.Reference, tl.Debit, tl.Credit
FROM TransactionLines tl
JOIN Transactions t ON tl.Transaction = t.id
WHERE tl.Account = {account_id}
ORDER BY t.Date DESC
Verify All Transactions Balance
SELECT id, Description, Total, IsBalanced
FROM Transactions
WHERE IsBalanced = false
Financial Reports
Balance Sheet
Shows Assets = Liabilities + Equity at a point in time.
Important: Parent accounts roll up child balances. Query only top-level parents (Parent = 0) to avoid double-counting.
-- Assets, Liabilities, Equity (top-level only)
SELECT Code, Name, Type, Balance
FROM Accounts
WHERE Type IN ('Asset', 'Liability', 'Equity')
AND Parent = 0
ORDER BY Type, Code
-- Net Income (for Equity section)
SELECT
COALESCE(SUM(CASE WHEN Type = 'Income' THEN Balance ELSE 0 END), 0) -
COALESCE(SUM(CASE WHEN Type = 'Expense' THEN Balance ELSE 0 END), 0) as NetIncome
FROM Accounts
WHERE Type IN ('Income', 'Expense')
AND id NOT IN (SELECT DISTINCT Parent FROM Accounts WHERE Parent != 0)
Presentation:
| Assets | |
|---|---|
| Cash & Bank Accounts | $X.XX |
| Accounts Receivable | $X.XX |
| Total Assets | $X.XX |
| Liabilities | |
|---|---|
| Accounts Payable | $X.XX |
| Due to Owner | $X.XX |
| Total Liabilities | $X.XX |
| Equity | |
|---|---|
| Retained Earnings | $X.XX |
| Net Income (Loss) | $X.XX |
| Total Equity | $X.XX |
| Total Liabilities + Equity | $X.XX |
Income Statement
Shows Revenue - Expenses = Net Income for a period.
SELECT Code, Name, Type, Balance
FROM Accounts
WHERE Type IN ('Income', 'Expense')
AND Balance != 0
AND id NOT IN (SELECT DISTINCT Parent FROM Accounts WHERE Parent != 0)
ORDER BY Type DESC, Code
Presentation:
| Income | |
|---|---|
| Service Revenue | $X.XX |
| Total Income | $X.XX |
| Expenses | |
|---|---|
| Software & Subscriptions | $X.XX |
| Professional Services | $X.XX |
| Total Expenses | $X.XX |
| Net Income (Loss) | $X.XX |
Trial Balance
Lists all accounts with non-zero balances. Debits should equal Credits.
SELECT
Code,
Name,
Type,
CASE WHEN Type IN ('Asset', 'Expense') THEN Balance ELSE 0 END as Debit,
CASE WHEN Type IN ('Liability', 'Equity', 'Income') THEN Balance ELSE 0 END as Credit
FROM Accounts
WHERE Balance != 0
AND id NOT IN (SELECT DISTINCT Parent FROM Accounts WHERE Parent != 0)
ORDER BY Code
Accounts Payable Aging
SELECT
v.Name as Vendor,
b.BillNumber,
b.BillDate,
b.DueDate,
b.AmountDue,
CASE
WHEN b.DueDate >= strftime('%s', 'now') THEN 'Current'
WHEN b.DueDate >= strftime('%s', 'now') - 2592000 THEN '1-30 Days'
WHEN b.DueDate >= strftime('%s', 'now') - 5184000 THEN '31-60 Days'
ELSE '60+ Days'
END as Aging
FROM Bills b
JOIN Vendors v ON b.Vendor = v.id
WHERE b.Status IN ('Open', 'Partial')
ORDER BY b.DueDate
Year-End Tax Reports
Date-parameterized queries for tax year reporting. Replace {start_date} and {end_date} with Unix timestamps (e.g., 2025: start=1735776000, end=1767312000).
Period Income Statement (P&L)
Sums TransactionLines by Income/Expense account for a date range (Schedule C core data):
SELECT a.Code, a.Name, a.Type,
SUM(tl.Debit) as Debits, SUM(tl.Credit) as Credits
FROM TransactionLines tl
JOIN Transactions t ON tl.Transaction = t.id
JOIN Accounts a ON tl.Account = a.id
WHERE a.Type IN ('Income', 'Expense')
AND t.Date >= {start_date} AND t.Date < {end_date}
GROUP BY a.Code, a.Name, a.Type
ORDER BY a.Type DESC, a.Code
Period Expense Detail
All expense transactions with individual line items, grouped by account:
SELECT t.Date, a.Code, a.Name, t.Description, t.Reference, tl.Debit, tl.Credit
FROM TransactionLines tl
JOIN Transactions t ON tl.Transaction = t.id
JOIN Accounts a ON tl.Account = a.id
WHERE a.Type = 'Expense'
AND t.Date >= {start_date} AND t.Date < {end_date}
ORDER BY a.Code, t.Date
Vendor Payment Summary
Total payments per vendor for 1099 determination ($600+ threshold):
SELECT v.Name as Vendor, COUNT(bp.id) as Payments, SUM(bp.Amount) as TotalPaid
FROM BillPayments bp
JOIN Bills b ON bp.Bill = b.id
JOIN Vendors v ON b.Vendor = v.id
WHERE bp.PaymentDate >= {start_date} AND bp.PaymentDate < {end_date}
GROUP BY v.Name
ORDER BY TotalPaid DESC
Period General Ledger
All transactions in the period with full detail:
SELECT t.Date, t.Description, t.Reference, t.Status,
a.Code, a.Name, tl.Debit, tl.Credit, tl.Memo
FROM TransactionLines tl
JOIN Transactions t ON tl.Transaction = t.id
JOIN Accounts a ON tl.Account = a.id
WHERE t.Date >= {start_date} AND t.Date < {end_date}
ORDER BY t.Date, t.id, a.Code
Point-in-Time Balance Sheet / Trial Balance
Use Accounts.Balance (cumulative) for businesses that started tracking in Grist during the reporting year. If prior-year data exists, subtract beginning-of-year balances. See the Financial Reports section for balance queries.
Note
: If
tl.TransactionJOIN fails due to the reserved word issue, fall back toget_recordson TransactionLines + programmatic joining.
Reconciliation Queries
Cleared Balance for Bank Account
Use get_records to avoid the Transaction reserved word issue:
# Step 1: Get all TransactionLines for Checking (id=14)
lines = get_records("TransactionLines", filter={"Account": [14]})
# Step 2: Get cleared transaction IDs
txn_ids = list(set(line["Transaction"] for line in lines))
cleared = sql_query(f"SELECT id FROM Transactions WHERE Status = 'Cleared' AND id IN (...)")
cleared_ids = set(row["id"] for row in cleared)
# Step 3: Sum Debit - Credit for cleared lines
cleared_balance = sum(
line["Debit"] - line["Credit"]
for line in lines
if line["Transaction"] in cleared_ids
)
Outstanding Items (Not Cleared by Bank)
SELECT t.id, t.Date, t.Description, t.Status,
tl.Debit, tl.Credit
FROM TransactionLines tl
JOIN Transactions t ON tl.Transaction = t.id
WHERE tl.Account = 14
AND t.Status != 'Cleared'
ORDER BY t.Date
Reconciliation History
SELECT id, StatementDate, StatementBalance,
ClearedBalance, Difference, Status
FROM Reconciliations
WHERE Account = 14
ORDER BY StatementDate DESC
Active Bank Rules
get_records("BankRules", filter={"Account": [14], "IsActive": [true]})