Save a Query
Goal
Save a question — "open deals by the account's industry, this quarter" — under a name, so that a chart, a report, a dashboard and an export can all ask the same question by naming it, instead of each carrying its own copy.
Why this exists
Copies of a question drift. Somebody tightens the chart's filter and not the report's; six months later the two disagree by four percent and nobody can say which is right, because each looks perfectly correct where it sits.
A saved query has one definition. Correct it once and everything that names it is corrected — including in Test and Production the next time the solution is imported, because a saved query travels in the solution like a table or a form.
It is a question, not access to an answer. Whoever runs a saved query sees exactly what their own permissions allow, exactly as they would in a list of the same records. Saving a query does not lend anybody your access, and pointing a query at a table someone cannot read does not let them read it.
Prerequisites
- You are signed in as a maker, with a solution and an environment selected.
- The tables the query reads already exist in that environment.
Steps
-
Open your solution and choose Saved Queries.
-
Select New. The query designer opens on its own page.
-
Give it a display name — the logical name fills itself in as you type.
-
Write a short description. Whoever points a dashboard at this query later is often not you, and a name rarely says which records the query leaves out.
-
Build the query. Simple is a table, its columns, a filter and a sort; Advanced adds related tables, grouping with measures, and the options; JSON is the document itself. The three are views of one query, so they can never disagree. Design a query walks through all of it.
The smallest useful document names a table and nothing else:
{"entity": "par_deal"}The full shape is the
parsware-query@1schema, which is also what you would hand an AI assistant asked to write one for you. -
Select Save. The platform checks three things: that the artifact is well formed, that the document is a valid query, and that it would actually run here — every field, join, grouping and measure resolved against this environment's real tables. A misspelled field is refused now, by you, rather than found later by whoever opens the dashboard.
-
Choose Preview to run it and see what comes back — either from the designer, or from the list with the query selected.
Two shapes: records or groups
Whether the document has an aggregate block is the whole difference, and the list says which
each query is in its Returns column.
Records — a page of matching rows, which is what a grid or an export wants:
{
"entity": "par_deal",
"select": ["par_name", "par_amount"],
"filter": {
"connector": "And",
"conditions": [
{ "field": "par_status", "operator": "Equals", "value": "Open" }
]
},
"order": [{ "field": "par_amount", "descending": true }]
}
Groups — totals, which is what a chart or a KPI tile wants. This one also joins, which is the thing a query can do that a view cannot: it reads a column from the deal's account. The designer builds all of this — the join is picked from a relationship rather than typed.
{
"entity": "par_deal",
"links": [
{
"alias": "acct",
"entity": "par_account",
"from": "par_accountid",
"to": "id",
"kind": "outer"
}
],
"aggregate": {
"groupBy": [{ "field": "acct.par_industry" }],
"measures": [{ "alias": "revenue", "function": "Sum", "field": "par_amount" }]
},
"order": [{ "field": "revenue", "descending": true }],
"top": 10
}
Once a table is joined under an alias, its columns are named alias.column everywhere in
the document — in filters, groupings, measures and sorts alike.
Every joined table is checked in its own right. If you can read deals but not accounts, this query is refused rather than quietly handing you account columns; if you can read only some accounts, you still see every deal, with the ones you may not see simply not attached.
Using a saved query
Anything that runs a query can name this one instead of holding its own — and a hand-written
app or control can too, through runtime.data.runSavedQuery("par_revenue_by_industry").
What runs it may narrow the query — add a filter, ask for a particular page, pick a time zone for date grouping — but it cannot change what the query reads, joins or measures. An added filter is combined with yours rather than replacing it, so a query that excludes cancelled orders keeps excluding them however it is used.
The name cannot be changed
The logical name is what every chart, report and dashboard stores, so renaming it would break all of them at once and silently. Everything else — the display name, the description, the whole document, even the table it reads — you can change whenever you like.
Moving it between environments
A saved query is a solution component, filed under the table it reads. Add it to your solution from that table's Manage components list (it appears under Saved Queries), and it exports and imports with everything else. On import it is checked against the target environment's tables the same way it was checked here.
Uninstalling the solution takes its saved queries with it. Anything elsewhere still naming one then fails by name, which is the honest outcome — the question belonged to the solution that left.
Troubleshooting
- "The query document is not valid JSON." — a missing comma or bracket. The box does not reformat what you type, so what you see is what was sent.
- "A saved query must name the table it reads." — add
"entity": "your_table". It is optional when a query is sent by a screen (the screen already knows the table) and required here, because a saved query is found by name alone. - "Unknown field …" — the name is misspelled, or it belongs to a joined table and needs its
alias in front of it (
acct.par_industry, notpar_industry). - "You did not join that table" — a field is qualified by an alias that no link declares.
Check the alias spelling against the
linkslist. - Preview says you may not read the table. — you cannot save a query you could not run; that is deliberate, because a query you cannot run is a query you cannot test. Ask an administrator for Read on the tables involved.
- A grouped query returns numbers that are too big. — a join in the one-to-many direction repeats the parent row once per match, and the totals count the repeats. Following a lookup (the usual case) cannot do this; joining to a child table can.