7.10.10. SQL-10 — _order_by and _order_by_descending
_order_by(key) adds an ORDER BY clause. The key shape decides
what the macro emits:
Key shape |
Emitted SQL |
|---|---|
|
|
|
|
|
|
|
|
|
|
7.10.10.1. Single-column order
let by_price <- _sql(db |> select_from(type<Car>)
|> _order_by(_.Price))
// SELECT "Id", "Name", "Price" FROM "Cars" ORDER BY "Price" ASC
_order_by_descending flips the direction:
let by_price_desc <- _sql(db |> select_from(type<Car>)
|> _order_by_descending(_.Price))
// ... ORDER BY "Price" DESC
7.10.10.2. Multi-column tuple key
A tuple-shaped key emits each tuple field as its own ORDER BY
column. Useful for primary-and-tie-breaker ordering:
let by_price_then_name <- _sql(db |> select_from(type<Car>)
|> _order_by((_.Price, _.Name)))
// ... ORDER BY "Price" ASC, "Name" ASC
If two rows tie on Price, the second column breaks the tie.
7.10.10.3. Computed key
The key can be a computed expression, not just a column reference.
Constants are inlined (the key fragment carries no bind), mirroring
computed _group_by keys:
let by_decile <- _sql(db |> select_from(type<Car>)
|> _order_by(_.Price / 10))
// ... ORDER BY ("Price") / (10) ASC
A tuple key may mix computed entries and plain columns
(_order_by((_.Price / 100, _.Name)) → ORDER BY ("Price") / (100)
ASC, "Name" ASC). A key referencing a runtime value (not a constant)
is rejected — inline a literal or drop to raw SQL.
A string-returning expression over the row is a computed key too —
_order_by(to_lower(_.Name)) → ORDER BY LOWER("Name") for a
case-insensitive sort. (A plain string variable with no column
reference is instead treated as a dynamic column name.)
7.10.10.4. Mixed ASC/DESC
_order_by and _order_by_descending emit every column in the
same direction. For per-column direction, use _order_by_keys:
it takes the key tuple plus a uint mask, where bit i sets key
i to DESC (LSB = first key, a clear bit stays ASC):
let mixed <- _sql(db |> select_from(type<Car>)
|> _order_by_keys((_.Price, _.Name), 2u))
// ... ORDER BY "Price" ASC, "Name" DESC
Mask 2u is 0b10 — bit 0 clear (Price ASC), bit 1 set
(Name DESC). 1u flips the first key, 3u flips both, 0u
is all-ascending (same as a plain tuple _order_by). Like the other
ordering steps, ordering may appear at most once in a chain.
7.10.10.5. Composes with _where and take
_order_by is just another chain stage — it composes with
filter, project, paginate, and aggregate operators in the natural
SQL order:
let cheap_top3 <- _sql(db |> select_from(type<Car>)
|> _where(_.Price > 50)
|> _order_by(_.Price)
|> take(3))
// ... WHERE "Price" > ? ORDER BY "Price" ASC LIMIT ?
Note the SQL clause order: WHERE first, ORDER BY next,
LIMIT last — same as the chain order.
7.10.10.6. Stable pagination
LIMIT/OFFSET without ORDER BY is non-deterministic —
SQLite is free to return rows in any order. Pair take/skip
with _order_by whenever you actually care about page boundaries.
See SQL-11 — take and skip: Paging.
See also
Full source: tutorials/sql/10-order_by.das
Previous tutorial: SQL-09 — _select Projections
Next tutorial: SQL-11 — take and skip: Paging