Inline Expressions
Define inline SQL expressions and display formatting on dataset metrics
Dataset metrics can include an expression field containing a SQL expression that transforms source data before aggregation. This lets you define calculations like unit conversions, conditional logic, and rounding directly on a metric -- without creating a full calculated metric.
The optional format field controls display formatting -- either as a simple string shorthand (currency, percent, number) or a full object with properties like decimals, currency, and locale. When a user drags the metric onto a card, the format seeds the card's default display settings.
When to Use Inline Expressions vs Calculated Metrics
| Feature | Inline Expression | Calculated Metric |
|---|---|---|
| Where defined | On a dataset metric (datasets[].fields.metrics[]) | In calculatedMetrics section |
| Scope | Single dataset -- can reference fields within the same dataset | Can span multiple datasets |
| Inputs | References fields by name directly in the expression | Named inputs with explicit dataset/field/aggregate mapping |
| Aggregation control | Automatic -- SUM applied by default if the expression is not pre-aggregated | Explicit -- you specify an aggregate per input |
| Use case | Simple transforms (unit conversion, rounding, conditional logic) | Complex KPIs (ratios across datasets, multi-level nesting) |
Expression Syntax
Two authoring styles are supported.
Plain field references:
Brace notation -- useful when field names contain special characters or for clarity:
Both produce the same result. At compile time, field names are resolved against the dataset's field inventory.
Referencing Other Metrics
Expression metrics can reference other metrics in the same dataset. If you have a metric amount_usd with expression amount_cents / 100, another metric can build on it:
Supported SQL Constructs
- Arithmetic:
+,-,*,/ CASE WHEN:CASE WHEN status = 'active' THEN amount ELSE 0 ENDCAST:CAST(amount_cents AS DECIMAL) / 100- Functions:
ROUND(...),COALESCE(...),CONCAT(...),ABS(...),NULLIF(...) EXTRACT:EXTRACT(YEAR FROM order_date)- Aggregate functions:
SUM(...),COUNT(...),AVG(...)-- makes the expression pre-aggregated
Expression syntax follows your database's SQL dialect (PostgreSQL, MySQL, BigQuery, etc.). Use functions supported by your connection type.
Examples
Currency Conversion
Percentage Metric
Conditional Logic
Rounding
Pre-Aggregated Expression
When the expression already contains aggregate functions, Semaphor uses it as-is instead of wrapping it in SUM(...).
Format Specification
The format field controls how a metric's values are displayed. It supports two forms: a string shorthand for common cases, and a full object for fine-grained control.
String Shorthand
For quick setup, pass a format type as a string:
Supported string values:
| Value | Display Effect | Example Output |
|---|---|---|
currency | Currency symbol (USD), 2 decimal places | $1,234.56 |
percent | Percent suffix, values treated as fractions | 27.5% |
percentage | Alias for percent | 27.5% |
number | Plain number, 2 decimal places | 1,234.56 |
scientific | Scientific notation | 1.23E+3 |
Object Form
For more control, pass a format object with specific properties:
Format Object Reference
| Property | Type | Applies To | Description |
|---|---|---|---|
type | string | All | number, currency, percent, percentage, scientific, date, string |
decimals | number | Numeric | Fixed decimal places (0-10) |
currency | string | currency | ISO currency code (e.g., USD, EUR, GBP). Defaults to USD |
locale | string | All | BCP 47 locale tag (e.g., en-US, de-DE). Defaults to en-US |
prefix | string | All | Text prepended to the value |
suffix | string | All | Text appended to the value |
thousandsSeparator | boolean | Numeric | Enable grouping separators. Defaults to true |
negativeStyle | string | Numeric | minus (default) or parentheses |
compact | boolean | Numeric | Use compact notation (e.g., 1.2K) |
scale | number | Numeric | Multiply value before display |
percentValueMode | string | percent | fraction (default, multiply by 100) or whole (display as-is) |
When using percentValueMode: fraction, a raw value of 0.275 displays as 27.5%. When using whole, the value 27.5 displays as 27.5%.
Format Precedence
When a user drags a metric with a format onto a card, the format seeds the card's default display settings. The precedence order is:
- User-set formatting (highest priority) -- any formatting the user explicitly configures on the card
- Semantic format -- the
formatvalue from the metric definition - Visual defaults -- Semaphor's built-in defaults
Formats are non-destructive
Format values only apply when a metric is first added to a card and only if the card has no existing format configured. They never overwrite user customizations.
Aggregation Behavior
Non-Aggregated Expressions
When an expression does not contain an aggregate function (SUM, COUNT, AVG, etc.), Semaphor automatically wraps it in SUM(...) when used as a metric. This mirrors the default behavior for regular numeric metrics.
Pre-Aggregated Expressions
If the expression already contains aggregate functions, Semaphor uses it as-is.
Non-Numeric Expressions
For non-numeric data types (string, date), COUNT is applied instead of SUM.
If you want full control over aggregation, include the aggregate function directly in the expression. For example, use AVG(amount) instead of amount (which defaults to SUM(amount)).
Validation Errors
When you save a domain template with metric expressions, Semaphor validates them. Two error codes are specific to inline expressions:
| Code | Meaning | Common Cause | Fix |
|---|---|---|---|
| E012 | Unknown field reference | The expression references a field name that does not exist in the dataset | Check spelling of field names; ensure the referenced field is defined in identifiers, dimensions, or metrics |
| E013 | Invalid expression | Circular dependency, unsupported AS aliasing, or other syntax issue | Review the expression for cycles (metric A references metric B which references A), remove AS aliases, and check SQL syntax |
For a complete list of validation errors, see Validation & Examples.
Restrictions
- AS aliasing --
amount_cents AS usdis not supported. Use the metric'snamefield instead. - Dimension expressions -- Only metrics support the
expressionfield. Dimension transforms should use calculated dimensions. - Cross-dataset references -- Inline expressions can only reference fields within the same dataset. For cross-dataset calculations, use calculated metrics.
- Braces in string literals -- String values containing
{or}are not supported inside expressions.
Best Practices
- Prefer
sourceFieldfor simple metrics -- If a metric maps directly to a database column with no transformation, usesourceFieldwithoutexpression. Expressions are for when you need to transform the value. - Use
NULLIFto prevent division by zero -- Writeamount / NULLIF(orders, 0)instead ofamount / orders. - Add a
formathint for user convenience -- Format hints save dashboard users from manually configuring number formatting every time they use the metric. - Keep expressions simple -- For complex multi-step calculations involving multiple datasets, use domain-level calculated metrics instead.
- Use descriptive
labelanddescription-- Help dashboard users understand what the transformed metric represents.