How to order and limit results¶
Control the order and size of your result set using .order_by() and .limit().
This guide uses the Sales model from Your first query:
from semolina import SemanticView, Metric, Dimension
class Sales(SemanticView, view="sales"):
revenue = Metric()
cost = Metric()
country = Dimension()
region = Dimension()
Sort ascending¶
Pass a bare field to .order_by() for ascending sort:
# ORDER BY revenue ASC
query = (
Sales.query()
.metrics(Sales.revenue)
.order_by(Sales.revenue)
)
Use .asc() on a field to be explicit about the direction:
# ORDER BY revenue ASC (same result as bare field)
query = (
Sales.query()
.metrics(Sales.revenue)
.order_by(Sales.revenue.asc())
)
Sort descending¶
Use .desc() for descending sort:
# ORDER BY revenue DESC
query = (
Sales.query()
.metrics(Sales.revenue)
.order_by(Sales.revenue.desc())
)
Control NULL positioning¶
By default, NULL positioning follows the warehouse backend’s behavior. Use
NullsOrdering to override it:
from semolina import NullsOrdering
# NULLs appear first (before non-NULL values)
query = (
Sales.query()
.metrics(Sales.revenue)
.order_by(Sales.revenue.desc(NullsOrdering.FIRST))
)
# NULLs appear last (after non-NULL values)
query = (
Sales.query()
.metrics(Sales.revenue)
.order_by(Sales.revenue.asc(NullsOrdering.LAST))
)
Value |
SQL generated |
Meaning |
|---|---|---|
|
|
NULLs sort before non-NULL values |
|
|
NULLs sort after non-NULL values |
|
(no NULLS clause) |
Backend decides (default) |
Sort by multiple fields¶
Pass multiple fields to .order_by() to sort by several columns. Fields are applied
left to right:
# ORDER BY revenue DESC, country ASC
query = (
Sales.query()
.metrics(Sales.revenue)
.dimensions(Sales.country)
.order_by(Sales.revenue.desc(), Sales.country.asc())
)
SELECT AGG("revenue"), "country"
FROM "sales"
GROUP BY ALL
ORDER BY "revenue" DESC, "country" ASC
SELECT MEASURE(`revenue`), `country`
FROM `sales`
GROUP BY ALL
ORDER BY `revenue` DESC, `country` ASC
Limit the result count¶
Use .limit(n) to cap the number of rows returned:
# LIMIT 10
query = Sales.query().metrics(Sales.revenue).limit(10)
n must be a positive integer. Passing zero or negative raises ValueError.
Passing a non-integer raises TypeError.
Build “top N” queries¶
Combine .order_by() and .limit() for “top N” queries:
# Top 10 countries by revenue
query = (
Sales.query()
.metrics(Sales.revenue)
.dimensions(Sales.country)
.order_by(Sales.revenue.desc())
.limit(10)
)
cursor = query.execute()
for row in cursor.fetchall_rows():
print(f"{row.country}: {row.revenue}")
Store and reuse order terms¶
.asc() and .desc() return OrderTerm instances. You can
store and reuse them:
from semolina import NullsOrdering
# Create reusable sort terms
revenue_desc = Sales.revenue.desc(NullsOrdering.LAST)
country_asc = Sales.country.asc()
query = (
Sales.query()
.metrics(Sales.revenue)
.dimensions(Sales.country)
.order_by(revenue_desc, country_asc)
)
See also¶
How to build queries – the full query API
How to filter queries – filter queries before ordering