XCubes

Formulas

A formula item computes its value from an expression written in the XCubes formula language. Formulas are attached to individual items in a dimension; the engine evaluates them when the cube is computed.

Basic expressions

A formula references sibling items by their code. Codes that start with a letter and contain only letters, digits, and underscores can be written bare. Numeric codes and codes with special characters must be wrapped in double quotes.

Revenue - COGS
"620200" + "22520"
"R&D" + "G&A"

The standard arithmetic operators +, -, *, / work as expected. Parentheses control precedence.

Summing multiple items

To sum a fixed list of items, write an explicit + chain:

ProductSales + ServiceSales + OtherRevenue

This is clearer and more predictable than SetSum(), which takes wildcard patterns (SetSum("Sales*")) and matches by code prefix. Reserve SetSum() for true wildcard aggregations ("everything starting with 6") rather than enumerated lists.

The self keyword

Some time-series functions accept the keyword self as their first argument — it refers to this same item at an adjacent period, so you don't repeat the item's own code. self is supported by Prior, Grow, Feed, FeedFrom, and YoY. For example, Prior(self; 1) reads this line's previous period, and Grow(self; 0.05) grows it 5% each period.

Functions that accumulate or read from the current period's own value — YTD, RollingSum, RollingAvg, Lag, PctChange — reject self, because referring to the value being computed would create a cycle. For those, pass the item's own code (e.g. YTD(Revenue)), or express same-line lookback with Prior(self) / Grow(self; …).

Function arguments use semicolons

Arguments to all functions are separated by semicolons (;), not commas:

Lag(Revenue; -1)
If(Condition; TrueValue; FalseValue)

(Lag's shift is signed — -1 is the previous data period, +1 the next.)

Item codes vs. reference names

Plain identifiers in a formula refer to sibling items in the same dimension. The functions Reference(), Prior(), PriorDelta() and Delay() take a reference name (a string in double quotes) that is resolved through the cube's registered cross-cube references — they do not refer to items. See Cube references.

How formulas behave at totals

When a formula item meets a total of another dimension — a quarter or year column, a scenario sum like ACT + PLAN, a subtotal row — the value in that cell depends on what kind of formula it is:

Two related rules:

Declaring how a formula row rolls up

The rules above are a guess from the formula's shape, and the guess is wrong for an amount that merely carries a division: Salary / 12 * Months at the year total reads (year's Salary ÷ 12) × year's Months, not the sum of the months. A formula item's Roll-up at totals setting (in the item editor, alongside the formula) replaces the guess with a declaration:

Roll-up at totals What the crossing total shows Use it for
Automatic (the default) the rules above: a formula with a / is recomputed from totals, any other adds up formulas whose shape already says what they are
Add up the rows the sum of the crossing's members, in every dimension, whatever the formula contains an amount computed with a division — a monthly salary, a depreciation charge, a fee from a rate
Recompute from totals the formula re-evaluated from its inputs' totals, in every dimension — including at a parent of a hierarchy, which otherwise always sums its children a true ratio of two totals — a margin, a conversion rate, churn over an opening base

The other aggregation settings (average, none, closing, opening) work on a formula item too; use average or none for a per-row factor or rate that has no meaningful total. "Different by dimension" lets one row add up over entities and recompute over time.

Before any number looks wrong. The rule in short: a formula containing a division is recomputed at a total from the totals of its inputs, so that total is not the sum of the rows above it. To make a total add up the rows instead, declare Add up the rows on the formula row, or express the total as a hierarchy (a hierarchy parent always adds up its children). The calculation order (solve order) does not change this. Whenever an undeclared formula that divides meets a formula total of another dimension, such as TOTAL = SetSum() over a list of employees, the cube editor shows an amber notice naming the row and the total, with Add up the rows and It's a ratio (which declares Recompute from totals for that dimension and keeps the numbers as they are). Either choice records your intent and clears the notice. The cube's diagnostics list the same finding as RATIO_CROSSING_REEVALUATED.

When the guess is caught out. After a recompute, XCubes compares every automatically recomputed crossing with the members it stands for. A total that lies outside the range of its members — 900 over twelve cells that each read 200 — cannot be any weighted reading of them, so the automatic rule was wrong for that row. Such a cell carries an amber corner in the grid: hover it for the finding, click it to declare Add up the rows or Leave total blank (the aggregation setting none). The card does not offer Recompute from totals, because that is the reading the check just disproved; if the row really is a ratio over an opening or closing balance, declare it in the item editor instead. The same finding is listed by the cube's diagnostics and counted by check_assertions, so an agent sees it without opening the grid. A row that is already declared is never second-guessed.

If you genuinely need "the sum of the computed cells" for a ratio-like item, declare Add up the rows on it rather than modelling a second total.

Full function list

XCubes ships with functions for aggregation, math, logic, time-series navigation, and cross-cube lookups. The complete list with signatures and examples is in the Formula function reference.