Reports and dashboards with SQL — or plain English
Query live business data in SQL — or describe the report in plain English and review the SQL it writes — then pin results to a shared dashboard.
By the end of this guide you will have asked a business question in plain English, read the SQL it produced, run it against your live data, charted the result, saved it, and placed it on a report page your team opens as its dashboard. In AxisIQ all of that happens in one place — the Analytics app — with no warehouse to load, no BI tool to connect and nothing to sync first.
It works this way because your object types are real tables. Orders, products, customers, invoices, and every type you created for the way your own business runs — each is queryable with ordinary read-only SQL: joins, aggregates, GROUP BY, the parts you already know. There is no overnight extract to wait for. The rows you query are the rows the order screen is showing.
One thing to know before you build on it: Analytics reads, and only reads. The limits are set out in full below.
Before you start
- A workspace with real data in it. Still setting up? Do the setup guide first — reports on three test records teach you nothing.
- Permission to read the types you want to report on — a query never sees more than you can, so use an account with the access the report should reflect.
- SQL is optional. Step 2 exists so it stays optional.
Step 1 — Read the schema instead of guessing at it
Open Analytics and start a new query. Beside the editor sits the schema explorer: every object type in your workspace and every field on it, with the exact names to type. Use it — most of the time spent fighting a reporting tool goes on guessing column names.
Four things to know before you write a line:
- Table names are type keys, usually plural — the built-in
invoicesandpayments, and your own types under the keys they were given, such asordersorcustomers. If that key collides with a SQL reserved word, wrap it in backticks. - Every type hands you
idandcreated_at, whether or not you added them yourself. Most time-series reports need nothing more thancreated_at. - Single-value fields are columns; multi-value fields are not. A choice field, a number, a date, a money amount, a link to one other record — all columns. A multi-select, or a field holding several linked records, has none, so plan the question around that.
- Deleted records are already gone. No "not deleted" condition to remember: what you can query is the live data.
Step 2 — Ask in plain English, then read what it wrote
Switch to the Ask AI tab and describe the question the way you would say it to a colleague: which customers spent the most last quarter, and across how many orders. What comes back is SQL, dropped into the editor, unrun.
Read it before you press run. The model proposes; you decide. You see the tables it chose, the date range it assumed, the way it defined "revenue" — and when it has read the question differently from how you meant it, editing one line of SQL beats re-phrasing the prompt.
The generated SQL goes through exactly the same read-only validation as SQL you typed by hand. There is no separate, more-trusted path for machine-written queries — nothing extra for you to take on faith.
When the answer is a single number you need once, Ask Axis will give it to you in conversation and no report has to exist.
Step 3 — Write it yourself when the question is yours
Once you know the shape of your data, typing the query is usually faster than describing it:
SELECT customers.name,
COUNT(*) AS invoice_count,
SUM(invoices.amount) AS billed
FROM invoices
JOIN customers ON customers.id = invoices.customer
WHERE invoices.issue_date >= '2026-01-01'
GROUP BY customers.name
ORDER BY billed DESC
That assumes an invoices type with an amount field and a customer link; swap in the type and field names your workspace actually uses from the schema explorer.
Common table expressions, set operations such as UNION, and window functions all work, so ranked lists, running totals and period-over-period comparisons need nothing outside the editor.
Step 4 — Chart it, export it, save it
The result panel does three jobs. It shows the table, with the time the query took. It switches views — bar, line, donut, or a single large metric — and lets you map which column is the label and which the value, so one query can serve several charts. And it exports the result as CSV.
When a query is worth keeping, save it: a name, the SQL, and the chart configuration you chose.
Saved SQL is re-checked against the same rules every time it runs. A query saved by someone with broader access does not carry those privileges to whoever opens it later — it is re-validated and re-filtered for the person running it.
Step 5 — Lay saved queries out as a report
A report is a page of widgets — each one a query drawn as a table, a chart or a single metric, arranged in rows. Each widget runs its own query when the page is opened, so you see the business as it stands at that moment, not a figure cached overnight.
The dashboards that survive contact with a real team look alike: two or three headline numbers, one trend line, and the tables somebody acts on — overdue invoices, stock about to run out. Build that, then stop. Set it as your home page so it is the first thing you see. Dashboards nobody opens are how reporting projects die.
Step 6 — Report on the work itself, not just on the records
The history of your Work Queues is queryable in the same way. Two extra tables sit in the schema explorer beside your object types: queue_items (where each item stands now — its stage, status, batch and when it entered that stage) and queue_events (every movement, from stage to stage, with who made it). Questions about the process become ordinary SQL:
- How long items sit in each stage before someone picks them up — dwell time, by stage.
- How much got through per stage, per day.
- How many items from a given batch never turned up — missing counts, per batch.
One caveat: those two tables carry the whole workspace's queue history, so they appear only for people whose queue access is workspace-wide — access to a single queue does not unlock them.
This is where the "one system" argument stops being abstract: your throughput report and your revenue report come off the same screen because they come off the same data. The operational side of it is described in how AxisIQ handles operations.
What this deliberately will not do
Three limits, stated plainly, so you design around them rather than discover them.
Read-only, permanently. One SELECT per query. No UPDATE, no INSERT, no DELETE, no stacking a second statement behind a semicolon. Analytics cannot change your business data, and no setting relaxes that. Corrections belong on the record screen or in Flows; reporting is not an editing tool.
It is an answers engine, not a bulk-export pipe. A result set stops at 1,000 rows, and a query gets about five seconds of engine time inside an eight-second budget for the whole request. Pass the row ceiling and the result is flagged as truncated rather than passing off the first 1,000 rows as the whole picture; run past the clock and the query is cut — one runaway query cannot take the workspace down with it. Aggregate in SQL and the ceiling rarely comes near you; when you genuinely need every row, the CSV export on the records list is the tool.
You see what you are allowed to see. Fields hidden from you come back empty, and records outside your access simply are not in the result. Sharing a report therefore cannot show a colleague anything they could not look up directly — the filtering is per person, per run, not baked in when the report was written. The full model is described under permissions.
Variations and edge cases
- A query that times out is nearly always scanning too wide. Narrow the date range, aggregate in SQL rather than pulling raw rows, and let a common table expression do the heavy filtering first.
- A report that returns nothing for one colleague and rows for you is usually correct behaviour, not a bug: check what their permissions allow.
- Reports do not run themselves. There is no scheduled or emailed report — someone opens the dashboard. Plan for a morning habit rather than an inbox.
- Multi-value fields are the one modelling constraint that bites in reporting. If you need to group by something, keep it single-value on the record.
It all lives in Analytics — included on every plan. Start with a 7-day trial — no card required.
FAQ
Can I write real SQL against my business data?
Yes — read-only SELECT queries with joins, aggregates, GROUP BY, common table expressions and window functions, run directly on your live records. Your object types are the tables, and the schema explorer lists every table and column name.
Can AxisIQ turn a plain-English question into SQL? Yes. Describe the question and a proposed query lands in the editor for you to review before running. It passes the same read-only validation as anything you write by hand, so the generated SQL is trusted no more than yours is.
Do I need a data warehouse or a BI tool to build dashboards? No. Reports run on your operational data where it already lives, and report pages are assembled from saved queries in the same workspace — nothing to export, nothing to keep in step.
Can someone see data they should not by opening a shared report? No. Every run is filtered for the person running it: fields they cannot read come back empty, records they cannot access do not appear, and the saved query is re-validated on each run rather than trusted from when it was saved.
Can I use reporting to update or delete records in bulk? No, and that is deliberate. Analytics can only read; bulk changes belong in Flows or on the records screen, and bulk extraction belongs in the CSV export on the records list.