Table read statement

The table read statement, table T = read ..., creates a new table at the point of declaration. It supports reads inside a local with scope and, combined with loop const, a different input path per iteration. Both this form and read ... as T remain available; existing read statements do not need rewriting.

Table of contents

Syntax

The header follows the usual table-declaration order: name, primary dimension and size constraints appear before = read, rather than after the source as in read ... as T. Each table read statement defines one table’s inputs and columns. The table is not assembled by appending several read statements targeting the same name.

Columns can be declared directly in a with block:

table Products[Sku] max 1000 = read "/sample/products.csv" with
  Sku : text
  Price : number

show table "Products" with Products.Sku, Products.Price

Table options

The brackets name the primary dimension. Here, Sku is read from the file and must be unique. Table size constraints (min, max, small, dash) are supported; without an explicit maximum, the default is 1m rows. min and max constrain row counts, not the number of matched files. For example, min 0 permits an empty table. The small range form is also supported: small 100..1000 sets a warning threshold of 100 rows and an error threshold of 1000 rows, not a minimum of 100 rows. These options go before = read.

Sources

File patterns can include wildcards to combine matching files. Unlike read ... as T, separate table read statements cannot append to the same table. The wildcard’s column mappings apply to every matched file. Keep separate read ... as T statements when different file patterns need different column mappings into one table.

Source Form Column declarations
File path or pattern read "/sample/products*.csv" Required in with
Dashboard upload read upload "products" Required in with
Path schema read '/sample/products.csv' Supplied by the schema; with is optional

Column declarations

For ordinary paths and uploads, the with block is required. Its entries can be typed columns (Name : type), named-schema inclusions (schema S), or a mixture of both. Undeclared file columns are ignored. Direct renaming, positional reads such as read(1), and computed or constant assignments are not supported in this inline block. Schemas can supply renamed columns, parsing rules, and computed columns instead. Inline columns do not support enum or table enum declarations.

Here a named schema supplies the prices, including a computed column, while Sku is declared directly:

schema ProductSchema with
  Price : number
  TaxRate : number
  PriceWithTax : number = schema.Price * (1 + schema.TaxRate)

table Products = read "/sample/products.csv" with
  schema ProductSchema
  Sku : text

show table "Prices including tax" with Products.Sku, Products.PriceWithTax

The order of named-schema inclusions and explicit columns matters: a later declaration replaces an earlier schema-provided column with the same name. For example, a quantity normally read as a number can instead be read as text for inspection:

schema SalesSchema with
  Sku : text
  Qty : number

table Sales = read "/sample/sales.csv" with
  schema SalesSchema
  Qty : text

show table "Raw quantities" with Sales.Sku, Sales.Qty

Here Sales.Qty is text and Sales.Sku still comes from the schema. This override rule does not allow declaring the same column twice directly with Name : type in one block.

Path schemas

With a matching path schema, use a single-quoted path and omit the with block. The schema supplies both the columns and their parsing rules:

schema '/sample/orders.csv' with
  OrderDate : date = read("OrderDate") date:"dd/MM/yyyy"
  Qty : number

table Orders = read '/sample/orders.csv'
show table "Orders" with Orders.OrderDate, Orders.Qty

Here 31/12/2026 is parsed as December 31, 2026. An optional with block may restate existing schema columns with matching types; it does not select a subset of columns. All schema columns remain available on the table.

Uploads

Dashboard uploads use the same form. min 0 allows the uploaded table to contain no rows:

table Products min 0 = read upload "products" with
  Sku : text
  Price : number

show table "Products" editable:"products" with
  Products.Sku
  Products.Price

Coexisting with ordinary reads

Both read forms can coexist in a script, even reading the same file with different column types. Unlike read ... as T, a table read statement can follow computations. Here the first read preserves the quantity text for inspection, while the second reads it as numbers for a total:

read "/sample/sales.csv" as RawSales with
  Qty : text

lineCount = count(RawSales.*)

table Sales = read "/sample/sales.csv" with
  Qty : number

show table "Original quantity text" with RawSales.Qty
show summary "Sales totals" with
  lineCount as "Sales lines"
  sum(Sales.Qty) as "Units sold"

Inside a with scope

A table read statement can also appear inside a with scope. Its table is local to that scope; only the returned value is exposed:

total = with
  table Sales = read "/sample/sales.csv" with
    Qty : number
  return sum(Sales.Qty)

show scalar "Units sold" with total

Inside a loop

The input path must still be known at compile time. Use loop const to read a different path in each iteration:

total = 0
loop const batch in 1..2
  batchQty = with
    table Sales = read "/sample/sales-\{batch}.csv" with
      Qty : number
    return sum(Sales.Qty)
  total = total + batchQty

show scalar "Units sold across both files" with total

This sums Qty from /sample/sales-1.csv and /sample/sales-2.csv. The with scope keeps each iteration’s Sales table local, while const makes batch usable in the input path. All reads use the run’s input snapshot; a table read statement does not see files written during the same run.

Limitations

Table read statements do not support expect [...] on the read declaration or create the special file and calendar dimensions. Establish relationships after the read, or use read ... as T when these read-time dimensions are needed.