Querying data
Working with where expressions
The where expression is a core component of building queries in Exposed, allowing you to filter data by specifying conditions. A where expression expects a boolean operator (Op<Boolean>), which evaluates to either true or false.
We’ve categorized the available conditions into the following groups:
Basic conditions
Basic conditions are simple comparisons, such as equality (eq) and inequality (neq).
eqChecks if an expression is equal to some value.
neqChecks if an expression is not equal to some value.
isNull()Returns
trueif this expression is null,falseotherwise.isNotNull()Returns
falseif this expression is null,trueotherwise.lessChecks if an expression is less than some value.
lessEqChecks if an expression is less than or equal to some value.
greaterChecks if an expression is greater than some value.
greaterEqChecks if an expression is greater than or equal to some value.
existsChecks if a subquery returns at least one row.
notExistsChecks if a subquery does not return any row.
isDistinctFromChecks if this expression is not equal to another value, with null treated as a comparable value.
isNotDistinctFromChecks if an expression is equal to another value, with null treated as a comparable value.
Logical conditions
Logical conditions are those that use logical operators, such as AND, OR, and NOT.
andReturns the result of performing a logical
andoperation between two expressions.orReturns the result of performing a logical
oroperation between two expressions.notReturns the inverse of an expression.
andIfNotNullReturns the result of performing a logical
andoperation between two expressions if the second one is not null.orIfNotNullReturns the result of performing a logical
oroperation between two expressions if the second is not null.compoundAnd()Reduces a list to a single expression by performing an
andoperation between all the expressions in the list.compoundOr()Reduces a list to a single expression by performing an
oroperation between all the expressions in the list.
Pattern-matching conditions
Conditions that allow you to check for a match in a pattern using operators, such as LIKE.
likeChecks if an expression matches the specified pattern.
val allMoviesLike = StarWarsFilmsTable.selectAll() .where { StarWarsFilmsTable.name like "The %" }notLikeChecks if an expression doesn't match the specified pattern.
val allMoviesNotLike = StarWarsFilmsTable.selectAll() .where { StarWarsFilmsTable.name notLike "The %" }regexpChecks if an expression matches a regular expression.
val allMatchingRegex = StarWarsFilmsTable.selectAll() .where { StarWarsFilmsTable.name regexp "^The(\\s\\w+){2}\$" }matchChecks whether an expression matches a given pattern based on a specific mode.
Supported only on MySQL and MariaDB.
Range conditions
To check if a value lies within a specified range, use the .between() function.
It checks if an expression is between the values from and to. Returns true if the expression is between the lower and upper range values (inclusive). Date and time values are also supported as arguments.
Collection conditions
To check if an expression is equal or not to any element from a list, use the inList or notInList operators.
Using inList with lists
The inList operator checks if an expression matches any value in a list. In the following example, the query selects all films with sequelId values of 6 or 4.
Using inList with Pairs or Triples
The inList operator can also handle multiple expressions, such as pairs or triples, to check for equality across multiple columns.
Using ANY and ALL
In addition to the IN operator, the ANY and ALL operators are available with any preceding comparison operator:
anyFrom() and allFrom() also accept subqueries, tables, and array expressions as arguments.
Conditional WHERE
When working with SQL databases, it is a rather common case to have a query with a WHERE clause that depends on certain conditions. These conditions often come from application logic or user input. Managing such conditions can become complex, especially with independent or nested conditions.
Imagine a form on a website where a user can optionally filter "Star Wars" films by a director and/or a sequel. To construct such a query, you can use the .andWhere() function:
In the above example, the query starts with selectAll(), which retrieves all rows from the StarWarsFilmsTable. Then, the let function is used to ensure that conditional WHERE clauses for the directorName and sequelId are applied only if values are provided.
Conditional joins
Sometimes, you may need to modify not just the WHERE clause but also the underlying table joins based on certain conditions. For example, filtering by an actor's name might require joining ActorsTable conditionally.
In these cases, you can use the .adjustColumnSet() and .adjustSelect() functions, which allow to extend and modify JOIN and SELECT parts of a query:
Aggregating and sorting data
Count
The .count() method is used to determine the number of rows matching a query. It is called on a Query object and returns the total count of rows.
The following example counts all rows where sequelId equals 8:
Order by
The .orderBy() function allows you to sort query results by specifying a list of columns and their sort order (ascending or descending).
In the following example, StarWarsFilmsTable.sequelId specifies the column to sort by and SortOrder.ASC sets the sort order to be ascending:
Group by
In .groupBy(), define fields and their functions by the .select() method.
Available field functions are: .count(), .sum(), .average(), .min() and .max().
Limiting result sets
You can use the .limit() function to prevent loading large data sets or to accomplish pagination by using the .offset() function.
Mapping fields with alias
Aliases allow preventing ambiguity between field names and table names. To use the aliased var instead of the original one, use the .alias() function:
Aliases also allow you to use the same table in a join multiple times:
And they can be used when selecting from sub-queries:
Custom Select Queries
A Query instance, which can be instantiated by calling .selectAll() or .select() on a Table or Join, has many extension functions for building complex queries. Some of these have already been mentioned above, like .where(), .groupBy(), and .orderBy().
If a SELECT query with a special clause is required, a custom extension function can be implemented to enable its use with other standard queries.
For example, MySQL index hints, which follow the table name in SQL, can be implemented on a SELECT query by using the following custom function and class: