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.