query
Retrieve data from a semantic model by defining measures, dimensions, filters, and time groupings, with support for inline extensions, complex aggregations, and SQL inspection.
Instructions
Query data from a semantic model. Call inspect(reference=".", entity_type="model") first to see available columns and measures.
Args:
source_model: One of three forms:
- Model name (string) — name of a saved model from models_summary, e.g. "orders".
- Inline ModelExtension (dict) — extend an existing model with extra columns/joins/measures
for this one query: {"source_name": "orders", "columns": [{"name": "double_amount", "sql": "amount * 2", "type": "DOUBLE"}]}.
- Inline SlayerModel (dict) — define a model ad-hoc:
{"name": "ad_hoc", "sql_table": "things", "data_source": "test", "columns": [...]}.
measures: Aggregated values to return. Each is a formula: {"formula": "*:count"},
{"formula": "revenue:sum / *:count", "name": "aov"} (arithmetic),
{"formula": "cumsum(revenue:sum)"} (cumulative sum),
{"formula": "change(revenue:sum)"} (period-over-period difference),
{"formula": "change_pct(revenue:sum)"} (period-over-period % change, e.g. month-over-month growth),
{"formula": "time_shift(revenue:sum, -1)"} (the shifted value itself, one time bucket back),
{"formula": "time_shift(revenue:sum, -1, 'year')"} (value from one year earlier, for custom arithmetic),
{"formula": "lag(revenue:sum, 1)"} (previous row via window function; shifts by row position, NULL at edges),
{"formula": "lead(revenue:sum, 1)"} (next row via window function), {"formula": "last(revenue:sum)"} (most recent),
{"formula": "rank(revenue:sum)"} (ranking). A bare name like {"formula": "aov"} resolves to a saved ModelMeasure on the model.
change / change_pct / time_shift are calendar-aware and partition-safe: change and change_pct compare
each row against the prior time bucket (one step back at the query's own granularity), while time_shift
compares at its explicitly requested offset and granularity. All three join on the same non-time
dimension values, so per-group series reset cleanly — safe for grouped queries like month-over-month
revenue by store.
For period-over-period growth, prefer change_pct (or change for the absolute delta); use time_shift
only when you need the shifted value itself as a term in your own arithmetic.
dimensions: List of dimension names to group by, e.g. ["status", "region"].
filters: Filter conditions as formula strings. Examples: "status == 'completed'",
"amount > 100", "status in ('a', 'b')", "status is None",
"name like '%acme%'". Filters on measures are automatically routed to HAVING.
Supports and/or: "status == 'a' or status == 'b'".
Filters can also reference computed measure names or contain inline transforms:
"change(revenue:sum) > 0", "last(change(revenue:sum)) < 0".
time_dimensions: Time grouping. Format: {"dimension": "created_at", "granularity": "day|week|month|quarter|year", "date_range": ["2024-01-01", "2024-12-31"]}.
order: Sorting. Format: {"column": "measure_or_dim_name", "direction": "asc|desc"}.
limit: Max rows to return.
offset: Number of rows to skip.
whole_periods_only: When true, snap date filters to time bucket boundaries based on granularity, exclude the current incomplete time bucket.
show_sql: When true, include the generated SQL in the response for debugging.
strict: Error instead of warn when a cross-model measure would broadcast or a producer filter would be dropped. Rejected with run-by-name execution — declare it on the stored query instead.
dry_run: When true, generate and return the SQL without executing it.
explain: When true, run EXPLAIN ANALYZE and return the query plan.
format: Output format — "markdown" (default, compact and LLM-friendly), "json" (structured), or "csv" (most compact). Case-insensitive.
distinct_dimension_values: Default True (Cube.js-style auto-dedup for dim-only queries — emits GROUP BY ). Set False to emit raw rows: no top-level GROUP BY, just SELECT <dimensions/time_dimensions> with the usual WHERE/ORDER BY/LIMIT. Any measure reference (in measures, filters, or order) raises an error in this mode.
Example: query(source_model="orders", measures=[{"formula": "*:count"}], dimensions=["status"], filters=["status == 'completed'"])
Before calling this tool, run search first, supplying the entities you're thinking of using (and/or the query itself via the query arg, or a free-text question). Read the returned memories and consider any matching example queries before formulating the final query.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| order | No | ||
| format | No | markdown | |
| offset | No | ||
| strict | No | ||
| dry_run | No | ||
| explain | No | ||
| filters | No | ||
| measures | No | ||
| show_sql | No | ||
| variables | No | ||
| dimensions | No | ||
| source_model | Yes | ||
| time_dimensions | No | ||
| whole_periods_only | No | ||
| distinct_dimension_values | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |