Skip to main content
A table variable holds a collection of values in rows and columns rather than a single number — an amortization schedule, a series of cash flows, a set of line items, a lookup grid. Whether a variable holds a table is determined by its value — produced by a calculation or supplied as input — not by its kind. The table kind (see Defining variables) is how you get the table-specific display options: named columns, per-column formats, and row labels. A table value given a scalar kind such as number still renders as a table, but every cell takes that kind’s formatting — thousands separators, the configured decimal places — and the columns fall back to generic headers. This page covers the authoring side; for the underlying value model — how tables are written, stored, and combined — see Tables.

When to use a table

Use a table variable when a quantity is naturally many values rather than one: a payment broken out month by month, a list of material costs, a grid of rate-by-term lookups. A variable that holds a single value should stay a scalar number, percent, or no_separator.

Rows versus columns

The authoring distinction that matters: columns are defined, rows are data. You name and format the columns when you author the variable; the rows are produced by a calculation or supplied as input, and there can be any number of them. Tables are 1-indexed — the first row and column are index 1. So you configure the shape across, not down.

Configuring columns

Each column has:
  • A name — the column’s label.
  • A kind — any of the scalar kinds a plain variable uses: number, percent, no_separator, duration, date, datetime, or time.
  • A format — how the column’s values are shown, from the vocabulary that kind takes: a decimal count such as decimals_2, or a date or duration format token such as date_short.
  • Unit options — an optional list of suggested units for the cells below, in order, the first being the primary one. Only number and no_separator columns have them, the same two kinds as a scalar variable. Each column is separate: an amounts column can offer USD while a quantities column beside it offers ct. Set them in the Units Offered list under the column. Everything on Unit options applies one level down.
You also set the starting row index — the number shown as the label of the first row, like the row numbers down the side of a spreadsheet. It is a display indicator only and does not change how the table is indexed in equations, which is always 1-based. The starting row index is usually 1; however, setting it to 0 is handy, for example, when displaying a cash-flow table whose initial flow is period 0 (CF[0]) — see reading the cash flow table. Columns have no unit field: each cell carries its own unit, supplied with the value, so the variable’s own unit is empty (see Tables as a stored value). A column’s unit options are not a unit either. They are the suggested units for the cells below, and a cell can hold any unit whatever the list says. A table variable has no unit options of its own: the cells are what a person fills in, so the list belongs to the column.

Columns of dates and durations

A table variable’s own kind is always table, so a column carries the kind and the format for the cells beneath it. That is what lets a payment schedule put a date column beside a currency column: each cell is read, stored, and rendered against its own column, and the column beside it is unaffected.
Everything on Authoring dates and durations applies one level down. A cell takes any spelling a scalar takes, today and now included, read through its column’s kind. today names a day and now names a day and a time, and the column decides how much of that survives: a datetime column keeps both from now, a date column keeps only the day from either, a time column takes now and refuses today, and a duration column refuses both. Two duration columns with different format tokens read the same 22:47 differently, because the token is a property of the column. A cell that cannot be read is named by its column — 'Date' cell '2/45/26' is not a valid date — because there is otherwise no way to identify which of forty values is wrong. A cell written as a date in a column that is not one of those kinds is named the same way, rather than reported as an arithmetic error.

Row labels

A table can optionally carry row labels, so its rows read by name rather than only by index — for example, labeling an amortization table’s rows by month, or a cost breakdown’s rows by line item. Row labels are a presentation aid; they name the rows without changing the values in them. Row labels are an independent option: a table can have row labels with or without a default table, or none at all, but accessed and set in the default table view.

Default table

A table variable can carry a default table — a complete table value used when a calculation provides none, the multi-value counterpart to a scalar default value. A value supplied from a default is recorded with default provenance. A default table is also independent of row labels: you can set a default table on its own, pair it with row labels, or use neither. A table variable with no default has none applied.

Presenting a table as a chart

The same table variable can be displayed as a bar or pie chart instead of a grid — the chart is a presentation choice over the underlying table. See Charts.