EclipseLink/UserGuide/JPA/Basic JPA Development/Querying/JPQL
|Mailing List • Forums • IRC|
- 1 JPQL
- 1.1 Select Queries
- 1.2 WHERE Clause
- 1.3 Update Queries
- 1.4 Delete Queries
- 1.5 Functions
- 1.6 EclipseLink Extensions (EQL)
The Java Persistence Query Language (JPQL) is the query language defined by JPA. JPQL is similar to SQL, but operates on objects, attributes and relationships instead of tables and columns. JPQL can be used for reading (SELECT), as well as bulk updates (UPDATE) and deletes (DELETE). JPQL can be used in a NamedQuery (through annotations or XML) or in dynamic queries using the EntityManager createQuery() API.
For more information, see Chapter 4 "Query Language" in the JPA Specification.
Select queries can be used to read objects from the database. Select queries can return a single object or data element, a list of objects or data elements, or an object array of multiple objects and data.
Select query examples
// Query for a List of objects. Query query = em.createQuery("Select e FROM Employee e WHERE e.salary > 100000"); List<Employee> result = query.getResultList(); // Query for a single object. Query query = em.createQuery("Select e FROM Employee e WHERE e.id = :id"); query.setParameter("id", id); Employee result2 = (Employee)query.getSingleResult(); // Query for a single data element. Query query = em.createQuery("Select MAX(e.salary) FROM Employee e"); BigDecimal result3 = (BigDecimal)query.getSingleResult(); // Query for a List of data elements. Query query = em.createQuery("Select e.firstName FROM Employee e"); List<String> result4 = query.getResultList(); // Query for a List of element arrays. Query query = em.createQuery("Select e.firstName, e.lastName FROM Employee e"); List<Object> result5 = query.getResultList();
The SELECT clause can contain object expressions, attribute expressions, functions, sub-selects, constructors and aggregation functions.
Aggregation functions can include summary information on a set of objects. These include MIN, MAX, AVG, SUM, COUNT. These functions can be used to return a single result, or can be used with a GROUP BY to return multiple results.
SELECT COUNT(e) FROM Employee e
SELECT MAX(e.salary) FROM Employee e
The NEW operator can be used with the fully qualified class name to return data objects from a JPQL query. These will not be managed objects, and the class must define a constructor that matches the arguments of the constructor and their types. Constructor queries can be used to select partial data or reporting data on objects, and get back a class instance instead of an object array.
SELECT NEW com.acme.reports.EmpReport(e.firstName, e.lastName, e.salary) FROM Employee e
The FROM clause defines what is being queried. A typical FROM clause will contain the entity name being queried and assign it an alias.
SELECT e FROM Employee e
JPQL allows for multiple root level objects to be queried. Caution should be used when doing this, as it can result in Cartesian products of the two table. The WHERE or ON clause should ensure the two objects are joined in some way.
SELECT e, a FROM Employee e, MailingAddress a WHERE e.address = a.address
The entity name used in JPQL comes from the name attribute of the @Entity annotation or XML. It defaults to the simple entity class name. EclipseLink also allows for the fully qualified class name of the entity to be used (as of EclipseLink 2.4).
SELECT e FROM com.acme.Employee e
A JOIN clause can also be used in the FROM clause. The JOIN clause allows any of the object's relationships to be joined into the query so they can be used in the WHERE clause. JOIN does not mean the relationships will be fetched, unless the FETCH option is included.
SELECT e FROM Employee e JOIN e.address a WHERE a.city = :city
JOIN can be used with OneToOne, ManyToOne, OneToMany, ManyToMany and ElementColleciton mappings. When used with a collection relationship you can join the same relationship multiple times to query multiple independent values.
SELECT e FROM Employee e JOIN e.projects p JOIN e.projects p2 WHERE p.name = :p1 AND p2.name = :p2
The FETCH option can be used on a JOIN to fetch the related objects in a single query. This avoids additional queries for each of the object's relationships, and ensures that the relationships have been fetched if they were LAZY. EclipseLink also supports batch fetching through query hints.
SELECT e FROM Employee e JOIN FETCH e.address
JOIN FETCH normally does not allow an alias, but as of EclipseLink 2.4 an alias is allowed. The alias should be used with caution, as it can affect how the resulting objects are built. Objects should normally always have the same data, no matter how they were queried, this is important for caching and consistency. This is only an issue if the alias is used in the WHERE clause on a collection relationship to filter the related objects that will be fetched. This should not be done, but is sometimes desirable, in which case the query should ensure it has been set to BYPASS the cache.
SELECT e FROM Employee e JOIN FETCH e.address a ORDER BY a.city
By default all joins in JPQL are INNER joins. This means that results that do not have the relationship will be filtered from the query results. To avoid this, a join can be defined as an OUTER join using the LEFT options.
SELECT e FROM Employee e LEFT JOIN e.address a ORDER BY a.city
The join condition used for a join comes from the mapping's join columns. This means that the JPQL user is normally free from having to know how every relationship is joined. In some cases it is desirable to append additional conditions to the join condition, normally in the case of outer joins. This can be done through the ON clause. The ON clause is defined in the JPA 2.1 draft, and is supported in EclipseLink 2.4. EclipseLink also supports usage of the ON clause between two root level objects.
SELECT e FROM Employee e LEFT JOIN e.address ON a.city = :city
SELECT e FROM Employee e LEFT JOIN MailingAddress a ON e.address = a.address
For INNER joins EclipseLink will normally append the join condition to the WHERE clause, but this can be configured in the DatabasePlatform.
Sub-selects in FROM clause
As of EclipseLink 2.4, sub-selects are supported in the FROM clause. This requires the database supports this functionality.
SELECT MAX(g.salary) FROM (SELECT AVG(e.salary) AS salary FROM Employee e GROUP BY e.address.city) g
ORDER BY clause
ORDER BY allows the ordering of the results to be specified. Multiple values can be ordered, either ascending (ASC) or descending (DESC). EclipseLink allows functions, sub-selects and other operations in the ORDER BY clause. EclipseLink allows objects expressions to be used in the ORDER BY. In the case of entity objects, they are ordered by their Id, in case of embeddable objects, they are ordered by all of their fields. EclipseLink (as of 2.4) also allows for NULL ordering to be specified (either FIRST or LAST).
SELECT e FROM Employee e ORDER BY e.lastName ASC, e.firstName, ASC
SELECT e FROM Employee e ORDER BY UPPER(e.lastName)
SELECT e FROM Employee e LEFT JOIN e.manager m ORDER BY m.lastName NULLS FIRST
SELECT e FROM Employee e ORDER BY e.address
GROUP BY Clause
GROUP BY allows for summary information to be computed on a set of objects. GROUP BY is normally used in conjunction with aggregation functions. EclipseLink supports using objects, functions and sub-selects in the GROUP BY clause.
SELECT AVG(e.salary), e.address.city FROM Employee e GROUP BY e.address.city
SELECT AVG(e.salary), e.address.city FROM Employee e GROUP BY e.address.city ORDER BY AVG(e.salary)
SELECT e, COUNT(p) FROM Employee e LEFT JOIN e.projects p GROUP BY e
The HAVING clause allows for the results of a GROUP BY to be filtered. EclipseLink supports using comparisons, objects, functions and sub-selects in the HAVING clause.
SELECT AVG(e.salary), e.address.city FROM Employee e GROUP BY e.address.city HAVING AVG(e.salary) > 100000
EclipseLink supports UNION, INTERSECT and EXCEPT operations (as of 2.4). UNION allows the results of two queries with equivalent result structures to be combined into a single query. The unique results from both queries will be returned. If the ALL option is used, then results found in both queries will be duplicated.
INTERSECT returns only the results that are found in both queries. EXCEPT removes the results from the second query from the results from the first query.
The JPA spec does not support union operations.
SELECT MAX(e.salary) FROM Employee e WHERE e.address.city = :city1 UNION SELECT MAX(e.salary) FROM Employee e WHERE e.address.city = :city2
SELECT e FROM Employee e JOIN e.phones p WHERE p.areaCode = :areaCode1 INTERSECT SELECT e FROM Employee e JOIN e.phones p WHERE p.areaCode = :areaCode2
SELECT e FROM Employee e EXCEPT SELECT e FROM Employee e WHERE e.salary > e.manager.salary
The WHERE clause is normally the main part of the query as it defines the conditions that filter what is returned. The WHERE clause can use any comparison operation, logical operation, functions, attributes, objects, and sub-selects. The comparison operations include =, <, >, <=, >=, <>, LIKE, BETWEEN, IS NULL, and IN. NOT can also be used with any comparison operation (NOT LIKE, NOT BETWEEN, IS NOT NULL, NOT IN). The logical operations include AND, OR, and NOT. EclipseLink also supports the REGEXP operation to perform regular expression comparisons (requires database to support regular expressions). EclipseLink allows for functions and sub-selects to be used with any operation.
e.firstName = 'Bob'
|<||less than|| |
e.salary < 100000
|>||greater than|| |
e.salary > :sal
|<||less than or equal|| |
e.salary <= 100000
|>||greater than or equal|| |
e.salary >= :sal
|LIKE||evaluates if the two string match, '%' and '_' are valid wildcards, and ESCAPE character is optional|| |
e.firstName LIKE 'A%' OR e.firstName NOT LIKE '%._%' ESCAPE '.'
|BETWEEN||evaluates if the value is between the two values|| |
e.firstName BETWEEN 'A' AND 'C'
|IS NULL||compares the value to null, databases may not allow or have unexpected results when using = with null|| |
e.endDate IS NULL
|IN||evaluates if the value is contained in the list|| |
e.firstName IN ('Bob', 'Fred', 'Joe')
e.salary - 1000
e.salary + 1000
e.salary * 2
e.salary / 2
|ABS||absolute value|| |
ABS(e.salary - e.manager.salary)
|CASE||defines a case statement|| |
CASE e.STATUS WHEN 0 THEN 'active' WHEN 1 THEN 'consultant' ELSE 'unknown' END
|COALESCE||evaluates to the first non null argument value|| |
|CONCAT||concatenates two or more string values|| |
CONCAT(e.firstName, ' ', e.lastName)
|CURRENT_DATE||the current date on the database|| |
|CURRENT_TIME||the current time on the database|| |
|CURRENT_TIMESTAMP||the current date-time on the database|| |
|LENGTH||the character/byte length of the character or binary value|| |
|LOCATE||the index of the string within the string, optionally starting at a start index|| |
|LOWER||convert the string value to lower case|| |
|MOD||computes the remainder of dividing the first integer by the second|| |
MOD(e.hoursWorked / 8)
|NULLIF||returns null if the first argument to equal to the second argument, otherwise returns the first argument|| |
|SQRT||computes the square root of the number|| |
|SUBSTRING||the substring from the string, starting at the index, optionally with the substring size|| |
SUBSTRING(e.lastName, 0, 2)
|TRIM||trims leading, trailing, or both spaces or optional trim character from the string|| |
TRIM(TRAILING FROM e.lastName), TRIM(e.lastName), TRIM(LEADING '-' FROM e.lastName)
|UPPER||convert the string value to upper case|| |
|CAST||casts the value to the database type|| |
|EXTRACT||extracts the date part from the date/time value|| |
|REGEXP||evaluates if the string matches the regular expression|| |
e.lastName REGEXP '^Dr\.*'
JPQL defines several special functions that are not database functions, but have special meaning in JPQL. These include INDEX, KEY, SIZE, IS EMPTY, TYPE, FUNCTION and TREAT. EclipseLink also defines several special functions FUNC, OPERATOR, SQL and COLUMN.
|INDEX||the index of the ordered List element, only supported with @OrderColumn|| |
SELECT l FROM Employee e JOIN e.toDoList l WHERE INDEX(l) = 1
|KEY||the key of the Map element|| |
SELECT p FROM Employee e JOIN e.priorities p WHERE KEY(p) = 'high'
|SIZE||the size of the collection relationships, this evaluates to a sub-select|| |
SELECT e FROM Employee e WHERE SIZE(e.managedEmployees) < 2
|IS EMPTY||evaluates to true if the collection relationship is empty, this evaluates to a sub-select|| |
SELECT e FROM Employee e WHERE e.managedEmployees IS EMPTY
|TYPE||the inheritance discriminator value|| |
SELECT p FROM Project p WHERE TYPE(p) = LargeProject
|TREAT||treat (cast) the object as its subclass value (JPA 2.1 draft)|| |
SELECT e FROM Employee JOIN TREAT(e.projects AS LargeProject) p WHERE p.budget > 1000000
|FUNCTION||call a database function (JPA 2.1 draft)|| |
SELECT p FROM Phone p WHERE FUNCTION('TO_NUMBER', e.areaCode) > 613
EclipseLink special functions
EclipseLink defines several special JPQL functions that allow performing database operations that are not possible in basic JPQL. These include FUNC, OPERATOR, SQL and COLUMN.
FUNC allows for a database function to be call from JPQL. It allows calling any database functions not supported directly in JPQL, and calling user or library specific functions. FUNC is database specific, in that it does not translate the function call in any way to support different databases as other JPQL functions do. FUNC can only be used to call functions with normal syntax, functions that require special syntax cannot be called with FUNC. FUNC has been replaced by FUNCTION in JPA 2.1, so FUNCTION should be used as of EclipseLink 2.4.
SELECT p FROM Phone p WHERE FUNC('TO_NUMBER', e.areaCode) > 613
SELECT FUNC('YEAR', e.startDate) AS YEAR, COUNT(e) FROM Employee e GROUP BY YEAR
FUNC Oracle Spatial examples
The following examples show how to use FUNC with Oracle Spatial queries:
SELECT a FROM Asset a, Geography geo WHERE geo.id = :id AND a.id IN :id_list AND FUNC('ST_INTERSECTS', a.geometry, geo.geometry) = 'TRUE'
SELECT s FROM SimpleSpatial s WHERE FUNC('MDSYS.SDO_RELATE', s.jGeometry, :otherGeometry, :params) = 'TRUE' ORDER BY s.id ASC
OPERATOR allows for any EclipseLink operator to be called. EclipseLink supports many database functions using standard operator names that are then translated to different databases. EclipseLink operators are supported on any database that has an equivalent function (or set of functions). The EclipseLink ExpressionOperator clas can be used to allow a DatabasePlatform to override an operator, or define custom operators. OPERATOR is similar to FUNC, but allows the function to be database independent, and allows calling functions that require special syntax.
The supported EclipseLink operators include:
SELECT e FROM Employee e WHERE OPERATOR('ExtractXml', e.resume, '@years-experience') > 10
SQL allows for the usage and integration of SQL within JPQL. SQL includes the SQL string to inline into the JPQL and the arguments to translate into the SQL string. The '?' character is used to define parameters within the SQL that are translated from the SQL function arguments. SQL allows for the calling of database functions with non standard syntax, the embedding of SQL literals, and performing any other SQL operations within JPQL. The SQL function offers an alternative to using native SQL queries just because one part of the query requires something that is not supported in JPQL. Now JPQL can still be used for the query, and the SQL function used for the SQL specific parts.
SELECT p FROM Phone p WHERE SQL('CAST(? AS CHAR(3))', e.areaCode) = '613'
SELECT SQL('EXTRACT(YEAR FROM ?)', e.startDate) AS YEAR, COUNT(e) FROM Employee e GROUP BY YEAR
SELECT e FROM Employee e ORDER BY SQL('? NULLS FIRST', e.startDate)
SELECT e FROM Employee e WHERE e.startDate = SQL('(SELECT SYSDATE FROM DUAL)')
COLUMN allows access to unmapped columns in an object's table. This can be used to access foreign key columns, inheritance discriminators, or primitive columns such as ROWID. COLUMN can also be used in JPQL fragments inside the @AdditionalCriteria annotation.
SELECT e FROM Employee e WHERE COLUMN('MANAGER_ID', e) = :id
SELECT e FROM Employee e WHERE COLUMN('ROWID', e) = :id
EclipseLink Extensions (EQL)
EclipseLink provides many extensions to the standard JPA JPQL. These extensions provide access to additional database features many of which are part of the SQL standard, provide access to native database features and functions, and provide access to EclipseLink specific features. EclipseLink JPQL extensions are referred to as the EclipseLink Query Language (EQL).
EclipseLink's JPQL extensions include:
- Less restrictions than JPQL, allows sub-selects and functions within operations such as LIKE, IN, ORDER BY, constructors, functions etc.
- Allow != in place of <>
- FUNC operation to call database specific functions (now FUNCTION in JPA 2.1)
- TREAT operation to downcast related entities with inheritance
- OPERATOR operation to call EclipseLink database independent functions (EL 2.4)
- SQL operation to mix SQL with JPQL (EL 2.4)
- CAST and EXTRACT functions (EL 2.4)
- REGEXP function for regular expression querying (EL 2.4)
- Usage of sub-selects in the SELECT and FROM clause (EL 2.4)
- ON clause support for defining JOIN and LEFT JOIN conditions (EL 2.4)
- Joins between independent entities (EL 2.4)
- Usage of an alias on a JOIN FETCH (EL 2.4)
- COLUMN operation to allow querying on non mapped columns (EL 2.4)
- UNION, INTERSECT, EXCEPT support (EL 2.4)
- Usage of object variables in =, <>, IN, IS NULL, and ORDER BY