Select¶
Table::select() returns a Select builder. Chain projections, computed
columns, filters, grouping, and ordering, then call .execute() to get a
Result<Table>.
Assume a live runtime and the trades table
Builder methods¶
| Method | Purpose |
|---|---|
.col(name) |
project one existing column |
.cols([names]) |
project several existing columns |
.agg(name, expr) |
add a computed or aggregated column |
.filter(pred) |
keep matching rows (Where, AND-combined) |
.by(name) / .by_expr(name, expr) |
group before aggregating |
.order_by([cols], desc) |
sort the result |
.execute() |
compile and run, returning Result<Table> |
Selecting columns¶
Project existing columns with .col (one) or .cols (several):
┌──────┬──────────────────────────────┐
│ sym │ price │
│ SYM │ F64 │
├──────┼──────────────────────────────┤
│ AAPL │ 100.0 │
│ MSFT │ 200.0 │
│ AAPL │ 110.0 │
│ GOOG │ 300.0 │
│ MSFT │ 210.0 │
├──────┴──────────────────────────────┤
│ 5 rows (5 shown) 2 columns (2 shown)│
└─────────────────────────────────────┘
Select * (no projection)¶
A select() with no .col/.cols/.agg projects every column — the SQL
SELECT *. It is handy as the base for a pure .filter:
let r = t.select().filter(col("sym").eq("MSFT")).execute()?;
// all three columns, only the MSFT rows
Computed columns¶
.agg(name, expr) names the result of any expression. When
the expression is element-wise (not an aggregation), you get a derived column
with the same number of rows:
Aggregations¶
Use the aggregation free functions or methods
inside .agg. Without .by, an all-aggregation select collapses to a
single summary row:
┌─────────────────────────────────────┐
│ total │
│ I64 │
├─────────────────────────────────────┤
│ 150 │
├─────────────────────────────────────┤
│ 1 rows (1 shown) 1 columns (1 shown)│
└─────────────────────────────────────┘
Add .by to compute one row per group, and stack several
.agg calls to compute many statistics in one pass:
let stats = t
.select()
.agg("total_size", sum(col("size")))
.agg("avg_price", avg(col("price")))
.agg("n", count(col("price")))
.agg("hi", max(col("price")))
.agg("lo", min(col("price")))
.by("sym")
.execute()?;
┌──────┬────────────┬───────────┬─────┬───────┬───────┐
│ sym │ total_size │ avg_price │ n │ hi │ lo │
│ SYM │ I64 │ F64 │ I64 │ F64 │ F64 │
├──────┼────────────┼───────────┼─────┼───────┼───────┤
│ AAPL │ 40 │ 105.0 │ 2 │ 110.0 │ 100.0 │
│ MSFT │ 70 │ 205.0 │ 2 │ 210.0 │ 200.0 │
│ GOOG │ 40 │ 300.0 │ 1 │ 300.0 │ 300.0 │
├──────┴────────────┴───────────┴─────┴───────┴───────┤
│ 3 rows (3 shown) 6 columns (6 shown) │
└─────────────────────────────────────────────────────┘
Conditional aggregation¶
To aggregate only the rows that match a predicate, filter inside the
aggregation: sum(col("x").filter(pred)). The builder rewrites this into an
efficient masked sum automatically. Here, per symbol, we sum only the buy
side alongside the unconditional total:
let sym = Value::sym_vec(&["AAPL", "AAPL", "MSFT", "MSFT"]);
let side = Value::sym_vec(&["B", "S", "B", "S"]);
let qty = Value::vec(&[10i64, 5, 20, 8]);
let orders = Table::new(&["sym", "side", "qty"], &[sym, side, qty])?;
let r = orders
.select()
.agg("buy_qty", sum(col("qty").filter(col("side").eq("B"))))
.agg("total_qty", sum(col("qty")))
.by("sym")
.execute()?;
println!("{r}");
┌──────┬─────────┬────────────────────┐
│ sym │ buy_qty │ total_qty │
│ SYM │ I64 │ I64 │
├──────┼─────────┼────────────────────┤
│ AAPL │ 10 │ 15 │
│ MSFT │ 20 │ 28 │
├──────┴─────────┴────────────────────┤
│ 2 rows (2 shown) 3 columns (3 shown)│
└─────────────────────────────────────┘
Filtering and ordering¶
.filter keeps matching rows (multiple calls are AND-combined) and
.order_by sorts the output. Both compose with everything above: