Skip to content

Ordering

Usually, queries are ordered before LIMIT and OFFSET are applied. Beam supports the standard SQL ORDER BY construct through the orderBy_ function.

orderBy_ works like the Haskell function sortBy, with some restrictions. Its first argument is a function which takes as input the output of the given query. The function should return a sorting key, which is either a single sort ordering or a tuple of them. A sort ordering specifies an expression and a direction by which to sort. The result is then sorted lexicographically based on these sort expressions. The second argument to orderBy_ is the query whose results to sort.

Use the asc_ and desc_ functions to specify the sort ordering over an arbitrary expression.

Note

Use nullsFirst_ and nullsLast_ to control the ordering of nulls. See advanced features for more information.

For example, to get the first ten albums when sorted lexicographically, use

limit_ 10  $
orderBy_ (asc_ . albumTitle) $
all_ (album chinookDb)
SELECT "t0"."AlbumId" AS "res0",
       "t0"."Title" AS "res1",
       "t0"."ArtistId" AS "res2"
FROM "Album" AS "t0"
ORDER BY "t0"."Title" ASC
LIMIT 10
SELECT "t0"."AlbumId" AS "res0",
       "t0"."Title" AS "res1",
       "t0"."ArtistId" AS "res2"
FROM "Album" AS "t0"
ORDER BY "t0"."Title" ASC
LIMIT 10;

-- With values: []

Again, note that the ordering in which you apply the limit_ and orderBy_ matters. In general, you want to sort before you limit or offset, to keep your result set stable. However, if you really want to sort a limited number of arbitrarily chosen rows, you can use a different ordering.

orderBy_ (asc_ . albumTitle) $
limit_ 10 $
all_ (album chinookDb)
SELECT "t0"."res0" AS "res0",
       "t0"."res1" AS "res1",
       "t0"."res2" AS "res2"
FROM
  (SELECT "t0"."AlbumId" AS "res0",
          "t0"."Title" AS "res1",
          "t0"."ArtistId" AS "res2"
   FROM "Album" AS "t0"
   LIMIT 10) AS "t0"
ORDER BY "t0"."res1" ASC
SELECT "t0"."res0" AS "res0",
       "t0"."res1" AS "res1",
       "t0"."res2" AS "res2"
FROM
  (SELECT "t0"."AlbumId" AS "res0",
          "t0"."Title" AS "res1",
          "t0"."ArtistId" AS "res2"
   FROM "Album" AS "t0"
   LIMIT 10) AS "t0"
ORDER BY "t0"."res1" ASC;

-- With values: []

Multiple ordering keys

You can specify multiple keys to order by as well. Keys are sorted lexicographically in the given direction, as specified in the SQL standard.

For example, we can sort all employees by their state of residence in ascending order and by their city name in descending order.

limit_ 10 $
orderBy_ (\e -> (asc_ (addressState (employeeAddress e)), desc_ (addressCity (employeeAddress e)))) $
all_ (employee chinookDb)
SELECT "t0"."EmployeeId" AS "res0",
       "t0"."LastName" AS "res1",
       "t0"."FirstName" AS "res2",
       "t0"."Title" AS "res3",
       "t0"."ReportsTo" AS "res4",
       "t0"."BirthDate" AS "res5",
       "t0"."HireDate" AS "res6",
       "t0"."Address" AS "res7",
       "t0"."City" AS "res8",
       "t0"."State" AS "res9",
       "t0"."Country" AS "res10",
       "t0"."PostalCode" AS "res11",
       "t0"."Phone" AS "res12",
       "t0"."Fax" AS "res13",
       "t0"."Email" AS "res14"
FROM "Employee" AS "t0"
ORDER BY "t0"."State" ASC,
         "t0"."City" DESC
LIMIT 10
SELECT "t0"."EmployeeId" AS "res0",
       "t0"."LastName" AS "res1",
       "t0"."FirstName" AS "res2",
       "t0"."Title" AS "res3",
       "t0"."ReportsTo" AS "res4",
       "t0"."BirthDate" AS "res5",
       "t0"."HireDate" AS "res6",
       "t0"."Address" AS "res7",
       "t0"."City" AS "res8",
       "t0"."State" AS "res9",
       "t0"."Country" AS "res10",
       "t0"."PostalCode" AS "res11",
       "t0"."Phone" AS "res12",
       "t0"."Fax" AS "res13",
       "t0"."Email" AS "res14"
FROM "Employee" AS "t0"
ORDER BY "t0"."State" ASC,
         "t0"."City" DESC
LIMIT 10;

-- With values: []