Query Parameters
Introduction
By default, when you filter data when exploring a data model via the Exploration UI or via a Dashboard, what happens behind the scene is as follows:
- Your model is compiled into a full SQL statement.
- The SQL is run against your database and returns a result set
- The filtering condition is applied on the result set, and the final result is displayed to you.
However, there are cases in which you require the filtering condition to be included in the model's SQL in step 1 instead of being applied only in step 3.
Example use cases
To draw a histogram representing the revenue distribution of customers from city X, you will need to calculate revenues of customers from city X first, and then have a second aggregation to group their revenue values into various bins and calculate bin size. The filter condition
WHERE city = 'X'
needs to be included in the first aggregation.In an international company, to calculate and display monetary values (like revenue) in different currencies, it is intuitive to allow end-users to freely insert exchange rate into the calculation from the familiar dashboard interface. With only static SQL, you will need to aggregate the revenue into one currency and then cross-join the result with an exchange rates table to intentionally create a "fan-out" situation. This is often a computationally expensive operation.
These complex analytics use cases can now be solved efficiently with Holistics's Query Parameters feature.
How it works
For example, you have an order_items_aggr
model which counts how many orders have a certain number of items:
- With Query Parameter
- No Query Parameter
Model order_items_aggr {
...
query: @sql
with aggr as (
select
oi.order_id
, count(*) as items_count
from ecommerce.order_items oi
left join ecommerce.orders o on oi.order_id = o.id
group by 1
)
select
items_count
, count(*) as orders_count
from aggr
group by 1
;;
}
Model order_items_aggr {
...
query: @sql
with aggr as (
select
oi.order_id
, count(*) as items_count
from ecommerce.order_items oi
left join ecommerce.orders o on oi.order_id = o.id
where {% filter(order_date_param) %} o.created_at {% end %}
group by 1
)
select
items_count
, count(*) as orders_count
from aggr
group by 1
;;
// Query param declaration
param order_date_param {
label: 'Order Created At'
type: 'datetime'
}
}
If you only want to check orders created on the date '2024-10-01'
, by default this is not possible because the final model does not have an "Order Created At" field to filter on. With Query Parameters, you can insert the filter condition inside the SQL:
- With Query Parameter
- No Query Parameter
# order_items_aggr model
with order_items_aggr as (
with aggr as (
select
oi.order_id
, count(*) as items_count
from ecommerce.order_items oi
left join ecommerce.orders o on oi.order_id = o.id
group by 1
)
select
items_count
, count(*) as orders_count
from aggr
group by 1
)
select
items_count,
orders_count
from order_items_aggr
# Not possible to filter orders by date
# order_items_aggr model
with order_items_aggr as (
with aggr as (
select
oi.order_id
, count(*) as items_count
from ecommerce.order_items oi
left join ecommerce.orders o on oi.order_id = o.id
# date filter from dashboard is applied INSIDE of the CTE
where date(o.created_at) = '2024-10-01'
group by 1
)
select
items_count
, count(*) as orders_count
from aggr
group by 1
)
select
items_count,
orders_count
from order_items_aggr
In the following section, we will walk you through the steps to set up and use query parameters.
Set up
To use Query Parameters in your analytics setup, you need to declare it in the Query Model first, and then (optionally) link your dashboard filters to the Query Parameters.
1. Declare Query Parameters in Query Model
To use Query Parameters in a Query Model, you will need to:
- Declare the parameters in the model definition with
param
parameter - Incorporate the query parameter in the main SQL using the
{% filter(param) %} column_name {% end %}
expression as "placeholder" for the incoming filter.
In the example above, we have the following model definition:
Model order_items_aggr {
...
// Query param declaration
param order_date_param {
label: 'Order Created At'
type: 'datetime'
}
query: @sql
with aggr as (
select
oi.order_id
, count(*) as items_count
from ecommerce.order_items oi
left join ecommerce.orders o on oi.order_id = o.id
// Placeholder for end-user filter
where {% filter(order_date_param) %} o.created_at {% end %}
group by 1
)
select
items_count
, count(*) as orders_count
from aggr
group by 1
;;
}
When you include your model in a dataset, you will see the parameter appears under the Fields list. You can drag it into the Conditions area, and use it similarly to how you use a filter with normal fields.
The full list of Query Model's parameters is documented in the AML Models - Query Model reference page.
2. Link Dashboard Filters to Query Parameters
If you need to interact with a Query Parameter from a dashboard, the process is similar to how you create a filter from a dataset field:
Advanced Use Case: Dynamic Dimension Selection
Assuming that you have a model with two dimensions: dim1
and dim2
, and you want to use a dashboard filter to dynamically choose dim1
or dim2
to include in your calculation. This can be implemented using Query Parameter and the CASE
statement as follows:
Model model_with_dynamic_dim {
type: 'query'
label: 'Model with dynamic dim'
...
param dimension_choice {
label: 'Selected Dimension'
type: 'text'
allowed_values: ["choice1", "choice2"]
}
dimension dynamic_dimension {
label: 'Dynamic Dimension'
type: 'text'
hidden: false
definition: @sql {{ #SOURCE.dynamic_dimension }};;
}
query: @sql
select CASE
WHEN {% filter(dimension_choice) %} 'choice1' {% end %} THEN dim1
WHEN {% filter(dimension_choice) %} 'choice2' {% end %} THEN dim2
ELSE 'unknown'
END as dynamic_dimension
from {{ #model_with_2_dims }}
;;
}
After that, you can create a dashboard filter from the dimension_choice
Query Parameter. Depending on the choice, either dim1
or dim2
will be selected thanks to the CASE
statement.