NetSuite SuiteQL Trial Balance and Comparative Trial Balance Query
This generator builds SuiteQL that totals posted general ledger lines into a trial balance for one subsidiary, accounting book and period range, plus a by-department version and a two-period comparative. Paste the output into a SuiteQL tool, the N/query module or a REST call to query/v1/suiteql.
Fill in
Internal ID from Setup > Company > Subsidiaries.
Exactly as shown in Setup > Accounting > Manage Accounting Periods.
Primary book is usually 1. Block 4 lists your books.
1. Trial balance by account (period range, one subsidiary)
SELECT a.acctnumber, a.fullname, BUILTIN.DF(a.accttype) AS account_type, SUM(NVL(tal.debit, 0)) AS debit, SUM(NVL(tal.credit, 0)) AS credit, SUM(NVL(tal.debit, 0)) - SUM(NVL(tal.credit, 0)) AS net FROM transactionaccountingline tal INNER JOIN transaction t ON t.id = tal.transaction INNER JOIN transactionline tl ON tl.transaction = tal.transaction AND tl.id = tal.transactionline INNER JOIN account a ON a.id = tal.account INNER JOIN accountingperiod ap ON ap.id = t.postingperiod WHERE tal.posting = 'T' AND tal.accountingbook = 1 AND tl.subsidiary = 1 AND ap.isyear = 'F' AND ap.isquarter = 'F' AND ap.startdate >= (SELECT startdate FROM accountingperiod WHERE periodname = 'Jan 2026' AND isyear = 'F' AND isquarter = 'F') AND ap.enddate <= (SELECT enddate FROM accountingperiod WHERE periodname = 'Mar 2026' AND isyear = 'F' AND isquarter = 'F') GROUP BY a.acctnumber, a.fullname, BUILTIN.DF(a.accttype) ORDER BY a.acctnumber
2. Trial balance by account and department
SELECT a.acctnumber, a.fullname, BUILTIN.DF(tl.department) AS department, SUM(NVL(tal.debit, 0)) AS debit, SUM(NVL(tal.credit, 0)) AS credit, SUM(NVL(tal.debit, 0)) - SUM(NVL(tal.credit, 0)) AS net FROM transactionaccountingline tal INNER JOIN transaction t ON t.id = tal.transaction INNER JOIN transactionline tl ON tl.transaction = tal.transaction AND tl.id = tal.transactionline INNER JOIN account a ON a.id = tal.account INNER JOIN accountingperiod ap ON ap.id = t.postingperiod WHERE tal.posting = 'T' AND tal.accountingbook = 1 AND tl.subsidiary = 1 AND ap.isyear = 'F' AND ap.isquarter = 'F' AND ap.startdate >= (SELECT startdate FROM accountingperiod WHERE periodname = 'Jan 2026' AND isyear = 'F' AND isquarter = 'F') AND ap.enddate <= (SELECT enddate FROM accountingperiod WHERE periodname = 'Mar 2026' AND isyear = 'F' AND isquarter = 'F') GROUP BY a.acctnumber, a.fullname, BUILTIN.DF(tl.department) ORDER BY a.acctnumber, department
3. Comparative trial balance: period A vs period B
SELECT
a.acctnumber,
a.fullname,
SUM(CASE WHEN ap.periodname = 'Feb 2026' THEN NVL(tal.debit, 0) - NVL(tal.credit, 0) ELSE 0 END) AS net_period_a,
SUM(CASE WHEN ap.periodname = 'Mar 2026' THEN NVL(tal.debit, 0) - NVL(tal.credit, 0) ELSE 0 END) AS net_period_b,
SUM(CASE WHEN ap.periodname = 'Mar 2026' THEN NVL(tal.debit, 0) - NVL(tal.credit, 0) ELSE 0 END)
- SUM(CASE WHEN ap.periodname = 'Feb 2026' THEN NVL(tal.debit, 0) - NVL(tal.credit, 0) ELSE 0 END) AS change_b_minus_a
FROM transactionaccountingline tal
INNER JOIN transaction t ON t.id = tal.transaction
INNER JOIN transactionline tl ON tl.transaction = tal.transaction AND tl.id = tal.transactionline
INNER JOIN account a ON a.id = tal.account
INNER JOIN accountingperiod ap ON ap.id = t.postingperiod
WHERE tal.posting = 'T'
AND tal.accountingbook = 1
AND tl.subsidiary = 1
AND ap.periodname IN ('Feb 2026', 'Mar 2026')
AND ap.isyear = 'F'
AND ap.isquarter = 'F'
GROUP BY a.acctnumber, a.fullname
ORDER BY a.acctnumber4. Helper: list accounting books and periods
SELECT id, name, isprimary FROM accountingbook; SELECT id, periodname, startdate, enddate, isadjust, closed FROM accountingperiod WHERE isyear = 'F' AND isquarter = 'F' ORDER BY startdate DESC
Verify in Setup > Records Catalog for your account: account.fullname (some accounts prefer accountsearchdisplayname), transactionaccountingline.debit, credit, posting and accountingbook, and accountingbook.isprimary (present when Multi-Book is enabled). Run each query once in sandbox and tie the totals to the standard Trial Balance report for one period before relying on it. SuiteQL tools run one statement at a time, so run the two helper queries separately.
Get your trial balance query tied out
Send us the query output and the standard report for one period and we will find where they differ and adjust the query for your books and subsidiaries.
Optional. The tool and every export work without this. No spam.
How the query works
Posted GL impact in NetSuite lives in transactionaccountingline: one row per transaction line per accounting book, with account, debit, credit, amount and a posting flag. The query joins it to transaction for the posting period, to transactionline for subsidiary and department, to account for number and type, and to accountingperiod for the date range. It keeps only posting = 'T' rows so non-posting transactions such as sales orders and purchase orders are excluded, and filters isyear and isquarter to 'F' so summary periods do not double count. Net is debit minus credit, so assets and expenses are positive and liabilities, equity and income are negative, the same sign convention as a trial balance.
Worked example and how to check it
With subsidiary 1, book 1 and Jan 2026 to Mar 2026, block 1 returns one row per account with activity in those three months. To check income and expense accounts, run the Income Statement (Reports > Financial > Income Statement) for the same subsidiary and the same period range and compare a few accounts. The standard Trial Balance report (Reports > Financial > Trial Balance) shows balances as of the end period, not activity for a range, so to tie balance sheet accounts to it, remove the startdate condition so every period up to the end date is included. The sum of the net column across all rows should be zero for a balanced ledger.
Comparative and budget vs actual
Block 3 puts two periods side by side using conditional sums, which is cheaper than two queries and keeps accounts aligned. Use it for month-over-month reviews or as the actuals half of a budget vs actual comparison: budget amounts live in separate budget records, so export them separately and join on account and period outside NetSuite, or use the Budget vs Actual report. For a general ledger detail extract, drop the GROUP BY and select t.tranid, t.trandate, BUILTIN.DF(t.type), tal.debit and tal.credit per line, filtered to one account, which reproduces the rows behind each trial balance figure.
Gotchas
Amounts in transactionaccountingline are in the subsidiary's base currency for that book, so querying several subsidiaries with different currencies and summing them gives a meaningless total. Consolidated figures need currency translation, which SuiteQL provides through BUILTIN.CONSOLIDATE; check its arguments in NetSuite help before using it. Adjustment periods are included because they are neither year nor quarter rows; exclude them with ap.isadjust = 'F' if you want operating months only. Period names are text and must match exactly, including spacing. SuiteQL respects the role's permissions, so a role without access to some subsidiaries returns partial results without an error.
Frequently Asked Questions
Which SuiteQL table holds NetSuite GL postings?
transactionaccountingline. Each row is the accounting impact of a transaction line in one accounting book, with account, debit, credit, amount, posting and accountingbook. Join it to transactionline on transaction and transactionline for subsidiary, department, class and location, and to transaction for date, period and type.
Why does my SuiteQL trial balance not match the NetSuite report?
Usual causes: the report shows inception-to-date balances while the query sums only the selected periods; the query includes several accounting books; summary year or quarter periods were not excluded; non-posting lines were not filtered; or the role running SuiteQL cannot see every subsidiary. Compare one account at a time using the line-level version.
How do I build a comparative trial balance in SuiteQL?
Filter to the periods you need and use conditional aggregation: SUM(CASE WHEN ap.periodname = 'Feb 2026' THEN debit minus credit ELSE 0 END) for each period column. This keeps every account on one row and lets you add a difference column. Block 3 in this tool generates the full query.
Can I get a general ledger detail report from SuiteQL?
Yes. Use the same joins without GROUP BY and select tranid, trandate, type, memo, debit and credit for one account and period range. Order by trandate and tranid. For large ranges, page through the results with limit and offset or run it through SuiteAnalytics Connect.
If you want controllers to ask for trial balances and variances in plain English and see the SuiteQL behind each answer, running on your own infrastructure, we can set that up.
Related Tools
NetSuite SuiteQL Transaction Query Generator
Pick a transaction type, date range and row limit and get ready-to-run SuiteQL for headers, lines and the REST call that executes it.
NetSuiteNetSuite SuiteQL System Notes Audit Query Generator
Build SuiteQL over the systemnote table to audit field changes by record, user and date range, with a transaction join and a field discovery query.
NetSuiteNetSuite Month End Close Checklist
A practical NetSuite period close checklist covering subledgers, inventory and manufacturing, accruals, reconciliations and period lock.
Developer ToolsNetSuite REST Web Services Headers and Query Parameters Reference
Every request header, response header, query parameter and base endpoint you use with SuiteTalk REST Web Services, with values, defaults and examples in one table.
More NetSuite tools
See all- NetSuite Saved Search Formula Generator
- NetSuite CSV Import Template Guide
- NetSuite Role Permission Matrix Worksheet
- NetSuite Inventory Costing Method Reference
- NetSuite License Cost Estimator
- NetSuite User Access Request Form Template
- NetSuite Custom Record Design Spec Template
- NetSuite SuiteScript Deployment Handover Template
- NetSuite Sandbox and Release Change Log Worksheet
Keep exploring
Free tools
- SuiteQL Query GeneratorFill in a table, columns, filter and sort and get a SuiteQL statement ready for the N/query module, the REST SuiteQL endpoint or the SuiteAnalytics Workbook.
- NetSuite SuiteQL Transaction Query GeneratorPick a transaction type, date range and row limit and get ready-to-run SuiteQL for headers, lines and the REST call that executes it.
- NetSuite SuiteQL Custom List and Custom Record Query GeneratorEnter a custom list or custom record script ID and its fields to get SuiteQL for its values, its records, a join from transactions, and a ready REST call.
ERP fixes and how-tos
- How to write and run SuiteQL queries in NetSuiteRun SuiteQL from Analytics > SuiteQL Query Tool or via N/query in SuiteScript. Syntax basics, joins, pagination and real examples for NetSuite reporting.
- N/query versus N/search: choosing the right SuiteScript data access moduleCompare NetSuite's N/query (SuiteQL) and N/search modules for performance, governance cost and capability, and decide which to use for joins, aggregation, sublist reads and large exports in SuiteScript 2.1.
- How to Set Up Budgets and Budget vs Actual in NetSuiteCreate budgets in NetSuite by account, department, class or location, import them by CSV, and run Budget vs Actual reports to track spend against plan.
Runs with your ERP
- BlackLine and Oracle NetSuite: Account Reconciliation ConnectorHow BlackLine pulls NetSuite balances, GL and bank transactions and saved searches for account reconciliation and matching, with setup steps and pitfalls.
- Configure One (Revalize) CPQ and Oracle NetSuite: quote and account syncHow Configure One (Revalize) CPQ syncs quotes, contacts and accounts with NetSuite through the Revalize Integration Hub, with data flows, setup and pitfalls.
AI on your ERP
- NetSuite Month-End Close With AI That Finds the Problems Before the DeadlineAI for NetSuite month-end close: find unposted items, unusual journals, intercompany gaps and accrual candidates with SuiteQL, with controller review on every step.
- AI agents for NetSuite manufacturing operationsAI agents for NetSuite manufacturing: WIP tracking, routing exceptions, and work order status grounded in SuiteQL, with human approval on anything that writes back.
Integrations
- How to add AI agents to Oracle NetSuiteHow to add AI agents to Oracle NetSuite: SuiteQL and REST tool layer, RESTlet writes, role-scoped tokens, human approval, and where a private model fits.
- How to use Claude with Oracle NetSuiteUse Claude with Oracle NetSuite through MCP connectors, the Anthropic API, AWS Bedrock or Vertex, plus the on-prem alternative for controlled data.