Skip to content

Window Functions

Window functions compute a value across a set of rows related to the current row. MountSQLI compiles ROW_NUMBER, RANK, DENSE_RANK, LAG, LEAD, FIRST_VALUE, LAST_VALUE, and NTILE with PARTITION BY / ORDER BY / frames.

db.from(orders)
.window("rn", { fn: "ROW_NUMBER", partitionBy: ["customerId"], orderBy: [{ column: "total", dir: "desc" }] })
.all();
// → ROW_NUMBER() OVER (PARTITION BY "customerId" ORDER BY "total" DESC) AS "rn"
.window("rank", { fn: "RANK", orderBy: [{ column: "score", dir: "desc" }] })
.window("dense", { fn: "DENSE_RANK", orderBy: [{ column: "score", dir: "desc" }] })

Compare a row to its neighbors:

.window("prevTotal", { fn: "LAG", column: "total", orderBy: [{ column: "createdAt", dir: "asc" }] })
.window("nextTotal", { fn: "LEAD", column: "total", orderBy: [{ column: "createdAt", dir: "asc" }] })
.window("first", { fn: "FIRST_VALUE", column: "total", orderBy: [{ column: "createdAt", dir: "asc" }] })
.window("bucket", { fn: "NTILE", value: 4, orderBy: [{ column: "score", dir: "desc" }] })

Add a frame to control the window range:

.window("running", {
fn: "SUM",
column: "total",
orderBy: [{ column: "createdAt", dir: "asc" }],
frame: { type: "ROWS", start: "UNBOUNDED PRECEDING", end: "CURRENT ROW" },
})

Top order per customer:

export async function topOrderPerCustomer() {
const rows = await db
.from(orders)
.window("rn", { fn: "ROW_NUMBER", partitionBy: ["customerId"], orderBy: [{ column: "total", dir: "desc" }] })
.all();
return rows.filter((r) => r.rn === 1);
}
  • Use partitionBy to reset the window per group (e.g. per customer).
  • Always orderBy inside the window — window order is not the query order.
  • Compute ranking in SQL; don’t sort and number in app code.
  • Forgetting orderBy in the window — the function has no defined order.
  • Expecting where() to filter window results — filter after with a subquery.