Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
In this tutorial, you build a sales analytics metric view on the TPC-H dataset. By the end, you'll have a metric view that:
- Joins orders and customers across multiple tables using a snowflake schema.
- Defines fields (also called dimensions) for time, geography, and order attributes.
- Calculates simple and complex measures including ratios, filtered aggregations, and window measures.
- Uses composability to build complex metrics from simpler measures.
- Defines a parameter to apply a discount rate at query time.
- Includes agent metadata for dashboards and AI tools.
If you're new to metric views, start with Create a metric view to learn the basics. This tutorial extends that foundation with real-world complexity.
Requirements
To complete this tutorial, you must have:
- A workspace enabled for Unity Catalog.
- A SQL warehouse or compute resource running Databricks Runtime 17.3 or above.
For the full list of privileges required to create a metric view, see Prerequisites.
The data model
The TPC-H dataset models a wholesale supply chain. This tutorial uses three tables joined in a snowflake schema:
ordersjoins tocustomerono_custkey = c_custkeycustomerjoins tonationonc_nationkey = n_nationkey
| Table | Role | Key columns |
|---|---|---|
orders |
Fact table (order transactions) | o_orderkey, o_custkey, o_totalprice, o_orderdate, o_orderstatus |
customer |
Dimension table (customer details) | c_custkey, c_name, c_mktsegment, c_nationkey |
nation |
Dimension table (country or region reference) | n_nationkey, n_name, n_regionkey |
Step 1: Create the metric view and open the editor
You can build this metric view in the Catalog Explorer UI, generate it with Genie Code, or write the full YAML definition directly. All three methods resolve to a single YAML definition that models the metric view. In each step that follows, select the Catalog Explorer UI or YAML editor tab to follow your preferred method. If you use the YAML editor, the example code in each step is the portion of the YAML definition that corresponds to what you build in that step.
Note
The YAML examples in this tutorial use the fields keyword. When you build a metric view in the low-code editor, the YAML it generates uses the equivalent dimensions keyword instead. See Fields.
If you're unfamiliar with the UI for creating metric views, see Create a metric view.
To create the metric view, in Catalog Explorer:
- Search for
samples.tpch.orders. - Click the table name.
- Click Create > Metric view and name the view.
For the detailed create steps, see Create a metric view. When the editor opens, use the UI tab to build interactively, or click the <> button to edit the YAML definition directly.
Step 2: Set up the metric view
Set a version and a description for the metric view. The version determines the YAML specification version, and the comment documents the metric view's purpose, which appears in Catalog Explorer. Azure Databricks manages the version for you.
Catalog Explorer UI
The version is defined for you. To add or edit the description after you save the metric view:
- In Catalog Explorer, search for the metric view and click its name.
- Click Description, then enter a description of the metric view. You can use the sample description shown in the YAML editor tab.
This text corresponds to the comment field in the YAML definition. For more ways to edit a metric view, see Edit a metric view.
YAML editor
version: 1.1
comment: |-
Sales analytics metric view for order performance analysis.
Joins orders with customers and geography.
Owner: Analytics Team
Last updated: 2025-01-15
Step 3: Define the source and joins
Define the primary source table and join related tables:
sourcesets the fact table (orders) as the grain.joinsbrings in customer data using a many-to-one relationship.- The nested
nationjoin demonstrates a snowflake schema pattern, joining throughcustomerto reach geographic data, where nation is a subdimension of customer.
Catalog Explorer UI
This example adds two joins, both Many-to-one, to model the snowflake schema.
To add the customer join:
- In the editor, click Join in the upper-right corner to open the Add join dialog.
- Search for
samples.tpch.customer, click the table name, then click Add. - Set the join condition to
o_custkey = c_custkey. - Under Join Cardinality, select Many-to-one. For guidance on choosing a cardinality, see Join cardinality.
Then add the nested nation join. Repeat the steps from the customer join, joining samples.tpch.nation on c_nationkey = n_nationkey. Nesting the join under customer models nation as a subdimension of customer.
For the full join dialog steps, see Step 2: Add a join.
YAML editor
source: SELECT * FROM samples.tpch.orders
joins:
- name: customer
source: samples.tpch.customer
'on': o_custkey = c_custkey
joins:
- name: nation
source: samples.tpch.nation
'on': c_nationkey = n_nationkey
Step 4: Define a filter
A filter limits the source data, and it applies to all queries on the metric view. This tutorial limits the metric view to recent data.
Catalog Explorer UI
To define the filter:
- In the editor, click
Filter in the upper-right corner.
- Use the drop-down menus to set the Column to
o_orderdate, the Operator to>=, and the Value to1995-01-01.
For more about filters, see Step 3: Define a filter.
YAML editor
filter: o_orderdate >= '1995-01-01'
Step 5: Define fields
Fields are the attributes users group and filter by. A field can be a categorical column (such as region or status) or an unaggregated numeric column (such as age or quantity) that users aggregate at query time.
Agent metadata
Each field and measure in this tutorial includes agent metadata properties that improve how your metric view works with dashboards and AI tools:
display_name: A readable label that appears in visualizations instead of the technical column name.synonyms: Alternate names that help AI tools like Genie discover fields and measures through natural language queries.format: How values display in downstream surfaces such as dashboards, notebooks, and SQL query results, for example as currency, number, or percentage.
These properties are optional but recommended. The field and measure definitions in the following steps include them inline.
Field definitions
This tutorial adds:
- Time fields:
order_date,order_month, andorder_yearat multiple granularities to support different analysis needs. - Transformed fields:
order_statusandorder_priority, which useCASEandSPLITto convert source codes into readable labels. - Joined fields:
customer_name,market_segment, andcustomer_nation, which reference joined tables using the join name. Nested join columns use chained dot notation, such ascustomer.nation.n_name, to traverse the snowflake schema.
Catalog Explorer UI
The editor adds all source columns to the Fields tab automatically. Edit, rename, remove, and add fields so that the metric view defines exactly the following. For each field, click its name to edit it or click
Add to create it, then set the expression in Builder or Custom mode. Set the Display name and Synonyms for each field as shown.
order_date: In Builder mode, select the
o_orderdatecolumn. Set display name toOrder Date.order_month: In Custom mode, enter
DATE_TRUNC('MONTH', order_date). Set display name toOrder Month.order_year: In Custom mode, enter
YEAR(order_date). Set display name toOrder Year.order_status: In Custom mode, enter the following expression. Set display name to
Order Statusand synonyms tostatus,fulfillment status.CASE o_orderstatus WHEN 'O' THEN 'Open' WHEN 'P' THEN 'Processing' WHEN 'F' THEN 'Fulfilled' ENDorder_priority: In Custom mode, enter
SPLIT(o_orderpriority, '-')[0]. Set display name toPriority.customer_name: In Builder mode, select the
c_namecolumn from the joinedcustomertable. Set display name toCustomer Name.market_segment: In Builder mode, select the
c_mktsegmentcolumn from the joinedcustomertable. Set display name toMarket Segmentand synonyms tosegment,industry.customer_nation: In Custom mode, enter
customer.nation.n_nameto reference the nestednationjoin. Set display name toCountryand synonyms tonation,country.
For the full field steps, see Step 4: Add fields.
YAML editor
fields:
- name: order_date
expr: o_orderdate
display_name: Order Date
- name: order_month
expr: "DATE_TRUNC('MONTH', order_date)"
display_name: Order Month
- name: order_year
expr: YEAR(order_date)
display_name: Order Year
- name: order_status
expr: |-
CASE o_orderstatus
WHEN 'O' THEN 'Open'
WHEN 'P' THEN 'Processing'
WHEN 'F' THEN 'Fulfilled'
END
display_name: Order Status
synonyms:
- status
- fulfillment status
- name: order_priority
expr: "SPLIT(o_orderpriority, '-')[0]"
display_name: Priority
- name: customer_name
expr: customer.c_name
display_name: Customer Name
- name: market_segment
expr: customer.c_mktsegment
display_name: Market Segment
synonyms:
- segment
- industry
- name: customer_nation
expr: customer.nation.n_name
display_name: Country
synonyms:
- nation
- country
Step 6: Define parameters
Parameters let you pass values into the metric view when you query it, so a single definition can serve many query variants. This tutorial adds a discount parameter that a later measure uses to calculate discounted revenue. The parameter has a default of 0, so queries that don't pass a value return undiscounted revenue. For more about parameters, see Use parameters with metric views.
Catalog Explorer UI
In the editor heading, click Add parameter. Enter discount as the name, then enter a default value of 0 and select the double data type.
YAML editor
parameters:
- name: discount
data_type: double
default: 0
Step 7: Define measures
Measures are the calculations users want to analyze. Define atomic measures first, then use composability to build complex metrics that reference earlier-defined measures with the MEASURE() function. Set the display_name, format, and synonyms for each measure as described in Agent metadata. This tutorial adds:
- Atomic measures:
order_count,total_revenue, andunique_customers, the simple aggregations that form the building blocks. - Composed measures:
avg_order_valueandrevenue_per_customer, which reference earlier-defined measures withMEASURE()instead of duplicating aggregation logic. Iftotal_revenuechanges, these measures automatically use the updated definition. See Composability. - Filtered measures:
open_order_revenueandfulfilled_order_revenue, which useFILTER (WHERE ...)to create conditional metrics without separate fields. - Parameterized measure:
discounted_revenue, which references thediscountparameter to apply a discount rate. See Use parameters with metric views. - Window measure:
t7d_customers, which calculates a rolling 7-day count of unique customers. See Window measures for more window measure patterns.
Catalog Explorer UI
The editor adds a sample COUNT(*) measure automatically. Edit or remove it and add measures so that the metric view defines exactly the following. For each measure, click
Add, then set the expression in Builder or Custom mode. Set the Display name, Format, and Synonyms as shown. Use 2 decimal places for currency formats and 0 decimal places for number formats.
- order_count: In Builder mode, select the Count distinct aggregation on
o_orderkey. Set display name toOrder Count, format to Number. - total_revenue: In Builder mode, select the Sum aggregation on
o_totalprice. Set display name toTotal Revenue, format to Currency (USD), synonyms torevenue,sales. - discounted_revenue: In Custom mode, enter
SUM(o_totalprice * (1 - discount)). Set display name toDiscounted Revenue, format to Currency (USD). - unique_customers: In Builder mode, select the Count distinct aggregation on
o_custkey. Set display name toUnique Customers, format to Number. - avg_order_value: In Custom mode, enter
MEASURE(total_revenue) / MEASURE(order_count). Set display name toAvg Order Value, format to Currency (USD), synonyms toAOV. - revenue_per_customer: In Custom mode, enter
MEASURE(total_revenue) / MEASURE(unique_customers). Set display name toRevenue per Customer, format to Currency (USD). - open_order_revenue: In Custom mode, enter
SUM(o_totalprice) FILTER (WHERE o_orderstatus = 'O'). Set display name toOpen Order Revenue, format to Currency (USD), synonyms tobacklog. - fulfilled_order_revenue: In Custom mode, enter
SUM(o_totalprice) FILTER (WHERE o_orderstatus = 'F'). Set display name toFulfilled Revenue, format to Currency (USD). - t7d_customers: In Custom mode, enter
COUNT(DISTINCT o_custkey). Then click + Window and configure a window ordered byorder_datewith rangetrailing 7 dayandlastsemiadditive aggregation. Set display name to7-Day Rolling Customers, format to Number.
For the full measure steps, see Step 5: Add measures.
YAML editor
measures:
- name: order_count
expr: COUNT(DISTINCT o_orderkey)
display_name: Order Count
format:
type: number
decimal_places:
type: exact
places: 0
abbreviation: compact
- name: total_revenue
expr: SUM(o_totalprice)
display_name: Total Revenue
format:
type: currency
currency_code: USD
decimal_places:
type: exact
places: 2
abbreviation: compact
synonyms:
- revenue
- sales
- name: discounted_revenue
expr: SUM(o_totalprice * (1 - discount))
display_name: Discounted Revenue
format:
type: currency
currency_code: USD
decimal_places:
type: exact
places: 2
abbreviation: compact
- name: unique_customers
expr: COUNT(DISTINCT o_custkey)
display_name: Unique Customers
format:
type: number
decimal_places:
type: exact
places: 0
abbreviation: compact
- name: avg_order_value
expr: MEASURE(total_revenue) / MEASURE(order_count)
display_name: Avg Order Value
format:
type: currency
currency_code: USD
decimal_places:
type: exact
places: 2
abbreviation: compact
synonyms:
- AOV
- name: revenue_per_customer
expr: MEASURE(total_revenue) / MEASURE(unique_customers)
display_name: Revenue per Customer
format:
type: currency
currency_code: USD
decimal_places:
type: exact
places: 2
abbreviation: compact
- name: open_order_revenue
expr: SUM(o_totalprice) FILTER (WHERE o_orderstatus = 'O')
display_name: Open Order Revenue
format:
type: currency
currency_code: USD
decimal_places:
type: exact
places: 2
abbreviation: compact
synonyms:
- backlog
- name: fulfilled_order_revenue
expr: SUM(o_totalprice) FILTER (WHERE o_orderstatus = 'F')
display_name: Fulfilled Revenue
format:
type: currency
currency_code: USD
decimal_places:
type: exact
places: 2
abbreviation: compact
- name: t7d_customers
expr: COUNT(DISTINCT o_custkey)
window:
- order: order_date
semiadditive: last
range: trailing 7 day
display_name: 7-Day Rolling Customers
format:
type: number
decimal_places:
type: exact
places: 0
Review the complete definition
After completing the steps above, your metric view has the following complete definition:
View the complete YAML definition
version: 1.1
parameters:
- name: discount
data_type: double
default: 0
source: SELECT * FROM samples.tpch.orders
joins:
- name: customer
source: samples.tpch.customer
'on': o_custkey = c_custkey
joins:
- name: nation
source: samples.tpch.nation
'on': c_nationkey = n_nationkey
filter: o_orderdate >= '1995-01-01'
comment: |-
Sales analytics metric view for order performance analysis.
Joins orders with customers and geography.
Owner: Analytics Team
Last updated: 2025-01-15
fields:
- name: order_date
expr: o_orderdate
display_name: Order Date
- name: order_month
expr: "DATE_TRUNC('MONTH', order_date)"
display_name: Order Month
- name: order_year
expr: YEAR(order_date)
display_name: Order Year
- name: order_status
expr: |-
CASE o_orderstatus
WHEN 'O' THEN 'Open'
WHEN 'P' THEN 'Processing'
WHEN 'F' THEN 'Fulfilled'
END
display_name: Order Status
synonyms:
- status
- fulfillment status
- name: order_priority
expr: "SPLIT(o_orderpriority, '-')[0]"
display_name: Priority
- name: customer_name
expr: customer.c_name
display_name: Customer Name
- name: market_segment
expr: customer.c_mktsegment
display_name: Market Segment
synonyms:
- segment
- industry
- name: customer_nation
expr: customer.nation.n_name
display_name: Country
synonyms:
- nation
- country
measures:
- name: order_count
expr: COUNT(DISTINCT o_orderkey)
display_name: Order Count
format:
type: number
decimal_places:
type: exact
places: 0
abbreviation: compact
- name: total_revenue
expr: SUM(o_totalprice)
display_name: Total Revenue
format:
type: currency
currency_code: USD
decimal_places:
type: exact
places: 2
abbreviation: compact
synonyms:
- revenue
- sales
- name: discounted_revenue
expr: SUM(o_totalprice * (1 - discount))
display_name: Discounted Revenue
format:
type: currency
currency_code: USD
decimal_places:
type: exact
places: 2
abbreviation: compact
- name: unique_customers
expr: COUNT(DISTINCT o_custkey)
display_name: Unique Customers
format:
type: number
decimal_places:
type: exact
places: 0
abbreviation: compact
- name: avg_order_value
expr: MEASURE(total_revenue) / MEASURE(order_count)
display_name: Avg Order Value
format:
type: currency
currency_code: USD
decimal_places:
type: exact
places: 2
abbreviation: compact
synonyms:
- AOV
- name: revenue_per_customer
expr: MEASURE(total_revenue) / MEASURE(unique_customers)
display_name: Revenue per Customer
format:
type: currency
currency_code: USD
decimal_places:
type: exact
places: 2
abbreviation: compact
- name: open_order_revenue
expr: SUM(o_totalprice) FILTER (WHERE o_orderstatus = 'O')
display_name: Open Order Revenue
format:
type: currency
currency_code: USD
decimal_places:
type: exact
places: 2
abbreviation: compact
synonyms:
- backlog
- name: fulfilled_order_revenue
expr: SUM(o_totalprice) FILTER (WHERE o_orderstatus = 'F')
display_name: Fulfilled Revenue
format:
type: currency
currency_code: USD
decimal_places:
type: exact
places: 2
abbreviation: compact
- name: t7d_customers
expr: COUNT(DISTINCT o_custkey)
window:
- order: order_date
semiadditive: last
range: trailing 7 day
display_name: 7-Day Rolling Customers
format:
type: number
decimal_places:
type: exact
places: 0
Create the metric view using SQL
If you're building this definition outside Catalog Explorer, run the following SQL to create the metric view:
CREATE OR REPLACE VIEW catalog.schema.tpch_sales_analytics
WITH METRICS
LANGUAGE YAML
AS $$
version: 1.1
parameters:
- name: discount
data_type: double
default: 0
source: SELECT * FROM samples.tpch.orders
joins:
- name: customer
source: samples.tpch.customer
'on': o_custkey = c_custkey
joins:
- name: nation
source: samples.tpch.nation
'on': c_nationkey = n_nationkey
filter: o_orderdate >= '1995-01-01'
comment: |-
Sales analytics metric view for order performance analysis.
Joins orders with customers and geography.
Owner: Analytics Team
Last updated: 2025-01-15
fields:
- name: order_date
expr: o_orderdate
display_name: Order Date
- name: order_month
expr: "DATE_TRUNC('MONTH', order_date)"
display_name: Order Month
- name: order_year
expr: YEAR(order_date)
display_name: Order Year
- name: order_status
expr: |-
CASE o_orderstatus
WHEN 'O' THEN 'Open'
WHEN 'P' THEN 'Processing'
WHEN 'F' THEN 'Fulfilled'
END
display_name: Order Status
synonyms:
- status
- fulfillment status
- name: order_priority
expr: "SPLIT(o_orderpriority, '-')[0]"
display_name: Priority
- name: customer_name
expr: customer.c_name
display_name: Customer Name
- name: market_segment
expr: customer.c_mktsegment
display_name: Market Segment
synonyms:
- segment
- industry
- name: customer_nation
expr: customer.nation.n_name
display_name: Country
synonyms:
- nation
- country
measures:
- name: order_count
expr: COUNT(DISTINCT o_orderkey)
display_name: Order Count
format:
type: number
decimal_places:
type: exact
places: 0
abbreviation: compact
- name: total_revenue
expr: SUM(o_totalprice)
display_name: Total Revenue
format:
type: currency
currency_code: USD
decimal_places:
type: exact
places: 2
abbreviation: compact
synonyms:
- revenue
- sales
- name: discounted_revenue
expr: SUM(o_totalprice * (1 - discount))
display_name: Discounted Revenue
format:
type: currency
currency_code: USD
decimal_places:
type: exact
places: 2
abbreviation: compact
- name: unique_customers
expr: COUNT(DISTINCT o_custkey)
display_name: Unique Customers
format:
type: number
decimal_places:
type: exact
places: 0
abbreviation: compact
- name: avg_order_value
expr: MEASURE(total_revenue) / MEASURE(order_count)
display_name: Avg Order Value
format:
type: currency
currency_code: USD
decimal_places:
type: exact
places: 2
abbreviation: compact
synonyms:
- AOV
- name: revenue_per_customer
expr: MEASURE(total_revenue) / MEASURE(unique_customers)
display_name: Revenue per Customer
format:
type: currency
currency_code: USD
decimal_places:
type: exact
places: 2
abbreviation: compact
- name: open_order_revenue
expr: SUM(o_totalprice) FILTER (WHERE o_orderstatus = 'O')
display_name: Open Order Revenue
format:
type: currency
currency_code: USD
decimal_places:
type: exact
places: 2
abbreviation: compact
synonyms:
- backlog
- name: fulfilled_order_revenue
expr: SUM(o_totalprice) FILTER (WHERE o_orderstatus = 'F')
display_name: Fulfilled Revenue
format:
type: currency
currency_code: USD
decimal_places:
type: exact
places: 2
abbreviation: compact
- name: t7d_customers
expr: COUNT(DISTINCT o_custkey)
window:
- order: order_date
semiadditive: last
range: trailing 7 day
display_name: 7-Day Rolling Customers
format:
type: number
decimal_places:
type: exact
places: 0
$$;
For other ways to create a metric view, see Create a metric view.
Step 8: Query your metric view
Query the metric view using business-friendly syntax. The MEASURE() function aggregates a measure at the grain of the fields you select.
Aggregate measures by dimension
This example aggregates measures across multiple fields. It returns total revenue, order count, and average order value by customer nation and market segment, ranked by highest revenue first:
SELECT
customer_nation,
market_segment,
MEASURE(total_revenue) AS total_revenue,
MEASURE(order_count) AS order_count,
MEASURE(avg_order_value) AS avg_order_value
FROM catalog.schema.tpch_sales_analytics
GROUP BY customer_nation, market_segment
ORDER BY total_revenue DESC;
Analyze a monthly trend
This example combines a time field with measures to track a trend. It returns total revenue and open order revenue (backlog) by month and order status:
SELECT
order_month,
order_status,
MEASURE(total_revenue) AS total_revenue,
MEASURE(open_order_revenue) AS open_order_revenue
FROM catalog.schema.tpch_sales_analytics
GROUP BY order_month, order_status
ORDER BY order_month;
Pass a parameter value
Because the metric view defines a parameter, you can call it as a table-valued function and pass a value at query time. The following query applies a 10% discount. Because discount has a default of 0, queries that omit the argument return undiscounted revenue:
SELECT
customer_nation,
MEASURE(total_revenue) AS total_revenue,
MEASURE(discounted_revenue) AS discounted_revenue
FROM catalog.schema.tpch_sales_analytics(discount => 0.1)
GROUP BY customer_nation
ORDER BY discounted_revenue DESC;
What you learned
You built a metric view that demonstrates:
| Feature | Example |
|---|---|
| Snowflake schema joins | Orders to customer to nation (nested many-to-one joins) |
| Time fields | Date, month, year granularity |
| Transformed fields | CASE statements, SPLIT functions |
| Simple measures | COUNT, SUM |
| Composability | avg_order_value and revenue_per_customer reference earlier-defined measures using MEASURE() |
| Filtered measures | FILTER (WHERE ...) for conditional aggregations |
| Window measures | Rolling 7-day customer count using trailing 7 day |
| Parameters | discount parameter applied in the discounted_revenue measure |
| Agent metadata | display_name, format, synonyms on fields and measures |
Additional resources
- Window measures to calculate rolling averages and year-to-date totals.
- Materialization for metric views to improve query performance for large datasets.
- Use metric views to use your metric view in AI/BI dashboards.