The jOOQ User Manual. Multiple Pages : SQL building : SQL Statements : The SELECT statement : The JOIN clause | previous : next |
All versions: 3.12 | 3.11 | 3.10 | 3.9 | 3.8 | 3.7 | Development versions: 3.13 | Unsupported versions: 3.6 | 3.5 | 3.4 | 3.3 | 3.2 | 2.6
The JOIN clause
Available in ✅ Open Source Edition ✅ Express Edition ✅ Professional Edition ✅ Enterprise Edition
jOOQ supports many different types of standard SQL JOIN operations:
- [ INNER ] JOIN
- LEFT [ OUTER ] JOIN
- RIGHT [ OUTER ] JOIN
- FULL OUTER JOIN
- CROSS JOIN
- NATURAL JOIN
- NATURAL LEFT [ OUTER ] JOIN
- NATURAL RIGHT [ OUTER ] JOIN
All of these JOIN methods can be called on org.jooq.Table types, or directly after the FROM clause for convenience. The following example joins AUTHOR and BOOK
Factory create = new Factory(connection, dialect); // Call "join" directly on the AUTHOR table Result<?> result = create.select() .from(AUTHOR.join(BOOK) .on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))) .fetch(); // Call "join" on the type returned by "from" Result<?> result = create.select() .from(AUTHOR) .join(BOOK) .on(BOOK.AUTHOR_ID.eq(AUTHOR.ID)) .fetch();
The two syntaxes will produce the same SQL statement. However, calling "join" on org.jooq.Table objects allows for more powerful, nested JOIN expressions (if you can handle the parentheses):
SELECT * FROM AUTHOR LEFT OUTER JOIN ( BOOK JOIN BOOK_TO_BOOK_STORE ON BOOK_TO_BOOK_STORE.BOOK_ID = BOOK.ID ) ON BOOK.AUTHOR_ID = AUTHOR.ID
// Nest joins and provide JOIN conditions only at the end create.select() .from(AUTHOR .leftOuterJoin(BOOK .join(BOOK_TO_BOOK_STORE) .on(BOOK_TO_BOOK_STORE.BOOK_ID.eq(BOOK.ID))) .on(BOOK.AUTHOR_ID.eq(AUTHOR.ID)));
- See the section about conditional expressions to learn more about the many ways to create org.jooq.Condition objects in jOOQ.
- See the section about table expressions to learn about the various ways of referencing org.jooq.Table objects in jOOQ
JOIN ON KEY, convenience provided by jOOQ
Surprisingly, SQL does not allow to formally JOIN on well-known foreign key relationship information. Naturally, when you join BOOK to AUTHOR, you will want to do that based on the BOOK.AUTHOR_ID foreign key to AUTHOR.ID primary key relation. Not being able to do this in SQL leads to a lot of repetitive code, re-writing the same JOIN predicate again and again - especially, when your foreign keys contain more than one column. With jOOQ, when you use code generation, you can use foreign key constraint information in JOIN expressions as such:
SELECT * FROM AUTHOR JOIN BOOK ON BOOK.AUTHOR_ID = AUTHOR.ID
create.select() .from(AUTHOR) .join(BOOK).onKey();
In case of ambiguity, you can also supply field references for your foreign keys, or the generated foreign key reference to the onKey() method.
The JOIN USING syntax
Most often, you will provide jOOQ with JOIN conditions in the JOIN .. ON clause. SQL supports a different means of specifying how two tables are to be joined. This is the JOIN .. USING clause. Instead of a condition, you supply a set of fields whose names are common to both tables to the left and right of a JOIN operation. This can be useful when your database schema has a high degree of relational normalisation. An example:
-- Assuming that both tables contain AUTHOR_ID columns SELECT * FROM AUTHOR JOIN BOOK USING (AUTHOR_ID)
// join(...).using(...) create.select() .from(AUTHOR) .join(BOOK).using(AUTHOR.AUTHOR_ID);
In schemas with high degrees of normalisation, you may also choose to use NATURAL JOIN, which takes no JOIN arguments as it joins using all fields that are common to the table expressions to the left and to the right of the JOIN operator. An example:
-- Assuming that both tables contain AUTHOR_ID columns SELECT * FROM AUTHOR NATURAL JOIN BOOK
// naturalJoin(...) create.select() .from(AUTHOR) .naturalJoin(BOOK);
Oracle's partitioned OUTER JOIN
Oracle SQL ships with a special syntax available for OUTER JOIN clauses. According to the Oracle documentation about partitioned outer joins this can be used to fill gaps for simplified analytical calculations. jOOQ only supports putting the PARTITION BY clause to the right of the OUTER JOIN clause. The following example will create at least one record per AUTHOR and per existing value in BOOK.PUBLISHED_IN, regardless if an AUTHOR has actually published a book in that year.
SELECT * FROM AUTHOR LEFT OUTER JOIN BOOK PARTITION BY (PUBLISHED_IN) ON BOOK.AUTHOR_ID = AUTHOR.ID
create.select() .from(AUTHOR) .leftOuterJoin(BOOK) .partitionBy(BOOK.PUBLISHED_IN) .on(BOOK.AUTHOR_ID.eq(AUTHOR.ID));