# SQL Queries and Reports Common queries and financial report templates. ## Contents - [Common Queries](#common-queries) - [Financial Reports](#financial-reports) - [Reconciliation Queries](#reconciliation-queries) ## Common Queries ### Unpaid Bills by Vendor ```sql 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 ```sql 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) ```sql SELECT Code, Name, Type, Balance FROM Accounts WHERE Balance != 0 ORDER BY Code ``` ### Owner Reimbursement Balance ```sql SELECT Balance FROM Accounts WHERE Code = '2203' ``` ### Expense Summary by Account ```sql 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 ```sql 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 ```sql 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. ```sql -- 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 ``` ```sql -- 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. ```sql 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. ```sql 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 ```sql 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): ```sql 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: ```sql 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): ```sql 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: ```sql 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](#financial-reports) section for balance queries. > **Note**: If `tl.Transaction` JOIN fails due to the reserved word issue, fall back to `get_records` on TransactionLines + programmatic joining. ## Reconciliation Queries ### Cleared Balance for Bank Account Use `get_records` to avoid the `Transaction` reserved word issue: ```python # 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) ```sql 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 ```sql SELECT id, StatementDate, StatementBalance, ClearedBalance, Difference, Status FROM Reconciliations WHERE Account = 14 ORDER BY StatementDate DESC ``` ### Active Bank Rules ```python get_records("BankRules", filter={"Account": [14], "IsActive": [true]}) ```