Build complex queries with Common Table Expressions, recursive queries, and window functions.
CTEs (Common Table Expressions) and window functions enable powerful analytical queries that would otherwise require multiple queries or complex subqueries.
| Feature | PostgreSQL | MySQL | SQLite | MSSQL | MongoDB |
|---|---|---|---|---|---|
| Non-recursive CTE | ✅ | ✅ 8.0+ | ✅ | ✅ | ❌ |
| Recursive CTE | ✅ | ✅ 8.0+ | ✅ | ✅ | ❌ |
| MATERIALIZED | ✅ 12+ | ❌ | ❌ | ❌ | ❌ |
| Window Functions | ✅ | ✅ 8.0+ | ✅ | ✅ | ✅ 5.0+ |
CTEs create named temporary result sets that you can reference in the main query.
Chain multiple CTEs together, with later CTEs able to reference earlier ones.
Traverse hierarchical data like org charts, category trees, and graph structures.
Warning: Recursive CTEs can cause infinite loops without proper termination. Always include a stopping condition or use CYCLE detection (PostgreSQL 14+).
Control whether PostgreSQL materializes CTE results or inlines them.
Pre-built patterns for common CTE use cases.
MongoDB doesn't have CTEs, but $lookup and
$graphLookup provide similar capabilities.
Perform calculations across rows without collapsing the result set.
ROW_NUMBER() - Unique sequential numberRANK() - Same rank for ties, gapsDENSE_RANK() - Same rank, no gapsNTILE(n) - Divide into n bucketsLAG() - Previous row valueLEAD() - Next row valueFIRST_VALUE() - First in partitionNTH_VALUE() - Nth in partitionCTEs make complex queries more readable by breaking them into logical steps. Name CTEs descriptively to document their purpose.
Always set a maximum depth for recursive queries. Include it in your termination
condition (e.g., WHERE depth < 100).
CTEs may be materialized (computed once) or inlined (recomputed each use). For complex CTEs referenced multiple times, check the query plan.
Window functions are often more efficient than self-joins for comparing rows within the same result set.