Calculated Metrics
Create reusable KPIs with token-based expressions and nested references
Calculated metrics combine existing fields into a single aggregated number -- a KPI. They produce values like profit margin, average order value, or conversion rate. The result appears in the VALUES area of a card.
Creating in the Explorer
The Explorer provides a guided builder for creating calculated metrics without writing code.
Steps
- Open the Explorer and click + Add Calculated Field
- Select Calculated Metric
- Enter a name (e.g., "Profit Margin")
- Choose an operation (e.g., Ratio)
- Select fields for Input A and Input B
- Choose aggregation functions for each input
- Click Create Metric
Supported Operations
For standard operations, you select two input fields (A and B) and an aggregation function for each. Semaphor builds the expression for you.
| Operation | Description | Example |
|---|---|---|
| Sum | Add two values | Revenue + Shipping |
| Difference | Subtract one value from another | Revenue - Cost |
| Ratio | Divide one value by another | Revenue / Orders |
| Percent of Total | Calculate percentage contribution | Region Sales / Total Sales |
| Custom | Write your own SQL expression | SUM({Amount} - {Discount}) / NULLIF(COUNT(DISTINCT {Order ID}), 0) |
Aggregation Functions
For standard operations, choose how each input field is aggregated before the calculation:
SUM, AVG, COUNT, COUNT DISTINCT, MIN, MAX
Example: Average Order Value
- Operation: Ratio
- Input A:
AmountwithSUMaggregation - Input B:
Order IDwithCOUNT DISTINCTaggregation - Result:
SUM(Amount) / COUNT(DISTINCT Order ID)
Custom Expressions
When none of the standard operations fit your calculation, select Custom to write a SQL expression directly. The UI switches from the two-input builder to an expression editor.
How it works
- Set the operation to Custom
- The Input A / Input B selectors are replaced by an expression editor
- Write your SQL expression using
{FieldName}tokens to reference fields - Click fields in the left panel to insert tokens at your cursor position
- Click Validate Expression to check for errors
- Click Create Metric
Token matching is case-insensitive. {Amount}, {amount}, and {AMOUNT} all resolve to the same field.
Example: Discounted Revenue per Unit
You want SUM(amount - discount) / SUM(quantity) -- a ratio where the numerator does row-level arithmetic before aggregating. This can't be expressed with the standard Ratio operation because Ratio aggregates each input independently.
Expression:
Result: Semaphor generates:
Example: Weighted Average Price
You want a quantity-weighted average price -- SUM(price * quantity) / SUM(quantity).
Expression:
When to use Custom vs standard operations
| Use standard operations when... | Use Custom when... |
|---|---|
| The calculation is a simple ratio, sum, or difference of two fields | The expression involves row-level arithmetic before aggregation |
| Each input needs a single aggregation function | You need multiple aggregate functions in one expression |
| You don't need conditional logic | You need CASE WHEN, COALESCE, or other SQL constructs |
You can also use Generate with AI to describe your calculation in plain English and have Semaphor generate the expression for you.
Not sure if you need a calculated metric or a calculated dimension? See Choosing the Right Type.
Defining in a Template
For version-controlled definitions, bulk configuration, or CI/CD workflows, define calculated metrics in the calculatedMetrics section of your domain template.
Expression Syntax
Expressions use {input_name} tokens as placeholders for field references. The tokens are replaced with fully-qualified SQL at query time.
Two Input Types
Column reference -- points to a physical column in a dataset:
Metric reference -- points to another calculated metric (enables nesting):
Aggregation Rules
There are two places aggregation can be specified, and the rules are:
1. Expression wraps the token in an aggregate function:
2. Expression uses bare tokens:
If a token has no aggregate in either place, validation fails with error E010.
Supported aggregates: SUM, COUNT, AVG, MIN, MAX, MEDIAN, DISTINCT
Example: Building a Custom Metric
Suppose you have an orders dataset with amount, quantity, and discount_amount fields.
Step 1 -- Define a base metric with a custom expression.
Revenue after discounts requires subtracting discount_amount from amount before summing. Place the arithmetic inside SUM() so it runs row-by-row:
Semaphor generates:
Step 2 -- Build a ratio metric on top.
Average revenue per unit references the metric from Step 1 and a column aggregate:
Semaphor expands the nested reference and generates:
Nesting Calculated Metrics
Calculated metrics can reference other calculated metrics. This is how you build layered KPIs:
At query time, Semaphor recursively expands nested references. The profit_margin metric resolves to:
Maximum nesting depth is 10 levels. Circular references (A references B which references A) are detected and rejected with error E001.
Cross-Dataset Metrics
When inputs reference fields from different datasets, Semaphor automatically generates separate CTEs to aggregate each dataset independently, then joins them. This prevents metric inflation from fan-out joins.
When grouped by order_month, Semaphor generates:
Cross-dataset metrics require a grain mapping when grouped by a calculated dimension, so Semaphor knows which column in each dataset maps to the same time grain.
Field Reference
| Field | Type | Required | Description |
|---|---|---|---|
label | string | Yes | Display name |
description | string | No | Help text |
expression | string | Yes | SQL expression with {input} tokens |
inputs | object | Yes | Map of input name to column or metric reference |
metricType | enum | No | base, derived, calculated. Defaults to derived |
aggregationStrategy | enum | No | default, symmetric_aggregate, aggregate_then_join, weighted |
format | object | No | Display formatting (see Format Spec below) |
tags | string[] | No | Categorization tags |
filters | array | No | Default filters applied to this metric |
Format Spec:
For a full reference of format properties, see Inline Expressions -- Format Object Reference.