diff --git a/jOOQ-website/src/main/resources/manual-2.5.xml b/jOOQ-website/src/main/resources/manual-2.5.xml index 499c4c8ac6..4b7ef83d6f 100644 --- a/jOOQ-website/src/main/resources/manual-2.5.xml +++ b/jOOQ-website/src/main/resources/manual-2.5.xml @@ -4,5201 +4,648 @@ The jOOQ User Manual. Multiple Pages

# Overview

-

This manual is divided into four main sections:

- +

TODO: overview here

- -
- jOOQ classes and their usage - -

Overview

-

jOOQ essentially has two packages:

-
    -
  • org.jooq: the jOOQ API. Here you will find interfaces for all - SQL concepts -
  • -
  • org.jooq.impl: the jOOQ implementation and factories. Most - implementation classes are package private, you can only access - them using the -
  • -
-

- This section is about the main jOOQ classes and the global - architecture. Most of the time, however, you will be using the - - in order to create queries - the way you're used to in SQL -

-
- +
+ Getting started with jOOQ + -
- The example database - -

Example CREATE TABLE statements

-

- For the examples in this manual, the same database will always be - referred to. It essentially consists of these entities created using - the Oracle dialect -

-CREATE TABLE t_language ( - id NUMBER(7) NOT NULL PRIMARY KEY, - cd CHAR(2) NOT NULL, - description VARCHAR2(50) -) +
+ Different use cases for jOOQ + -CREATE TABLE t_author ( - id NUMBER(7) NOT NULL PRIMARY KEY, - first_name VARCHAR2(50), - last_name VARCHAR2(50) NOT NULL, - date_of_birth DATE, - year_of_birth NUMBER(7) -) + +
+ jOOQ as a SQL builder + +
-CREATE TABLE t_book ( - id NUMBER(7) NOT NULL PRIMARY KEY, - author_id NUMBER(7) NOT NULL, - title VARCHAR2(400) NOT NULL, - published_in NUMBER(7) NOT NULL, - language_id NUMBER(7) NOT NULL, - FOREIGN KEY (AUTHOR_ID) REFERENCES T_AUTHOR(ID), - FOREIGN KEY (LANGUAGE_ID) REFERENCES T_LANGUAGE(ID) -) +
+ jOOQ as a SQL builder with code generation + +
-CREATE TABLE t_book_store ( - name VARCHAR2(400) NOT NULL UNIQUE -) +
+ jOOQ as a SQL executor + +
-CREATE TABLE t_book_to_book_store ( - book_store_name VARCHAR2(400) NOT NULL, - book_id INTEGER NOT NULL, - stock INTEGER, - PRIMARY KEY(book_store_name, book_id), - CONSTRAINT b2bs_book_store_id - FOREIGN KEY (book_store_name) - REFERENCES t_book_store (name) - ON DELETE CASCADE, - CONSTRAINT b2bs_book_id - FOREIGN KEY (book_id) - REFERENCES t_book (id) - ON DELETE CASCADE -) -

- More entities, types (e.g. UDT's, ARRAY types, ENUM types, etc), - stored procedures and packages are introduced for specific examples -

- +
+ jOOQ for CRUD + +
+
- -
- The Factory class - -

The Factory and the jOOQ API

-

- jOOQ exposes a lot of interfaces and hides most implementation facts - from client code. The reasons for this are: -

-
    -
  • Interface-driven design. This allows for modelling queries in a fluent API most efficiently
  • -
  • Reduction of complexity for client code.
  • -
  • API guarantee. You only depend on the exposed interfaces, not concrete (potentially dialect-specific) implementations.
  • -
-

- The - class is the main class from where you will create all jOOQ objects. - The Factory implements - and needs to be instanciated with the Configuration's properties: -

-
    -
  • : - The dialect of your database. This may be any of the currently - supported database types
  • -
  • : - An optional JDBC Connection that will be re-used for the whole - lifecycle of your Factory
  • -
  • : - An optional JDBC DataSource that will be re-used for the whole - lifecycle of your Factory. If you prefer using DataSources over - Connections, jOOQ will internally fetch new Connections from - your DataSource, conveniently closing them again after query execution. - This is particularly useful in J2EE or Spring contexts.
  • -
  • : - An optional runtime configuration.
  • -
-

If you are planning on using several RDBMS (= SQLDialects) or - several distinct JDBC Connections in your software, this will mean - that you have to create a new Factory every time.

- -

Factory settings

-

- The jOOQ Factory allows for some optional configuration elements to be used by advanced users. - The class is a JAXB-annotated - type, that can be provided to a Factory in several ways: -

-
    -
  • In the constructor. This will override default settings below
  • -
  • From a location specified by a JVM parameter: -Dorg.jooq.settings
  • -
  • From the classpath at /jooq-settings.xml
  • -
  • From the settings defaults, as specified in - http://www.jooq.org/xsd/jooq-runtime-2.1.0.xsd -
  • -
-

- Subsequent sections of the manual contain some more in-depth explanations about these settings: -

-
    -
  • - -
  • -
  • - -
  • -
-

- Please refer to the jOOQ runtime configuration XSD for more details:
- http://www.jooq.org/xsd/jooq-runtime-2.1.0.xsd -

- -

Factory subclasses

-

- There are a couple of subclasses for the general Factory. Each SQL - dialect has its own dialect-specific factory. For instance, if you're - only using the MySQL dialect, you can choose to create a new Factory - using any of the following types: -

-// A general, dialect-unspecific factory -Factory create = new Factory(connection, SQLDialect.MYSQL); - -// A MySQL-specific factory -MySQLFactory create = new MySQLFactory(connection); -

- The advantage of using a dialect-specific Factory lies in the fact, - that you have access to more proprietary RDMBS functionality. This may - include: -

-
    -
  • Oracle's - pseudo columns and functions
  • -
  • MySQL's encryption functions
  • -
  • PL/SQL constructs, pgplsql, or any other dialect's ROUTINE-language (maybe in the future)
  • -
-

- Another type of Factory subclasses are each generated schema's - factories. If you generate your schema TEST, then you will have access - to a TestFactory. This will be useful in the future, when access to - schema artefacts will be unified. Currently, this has no use. -

- -

Static Factory methods

-

- With jOOQ 2.0, static factory methods have been introduced in order to - make your code look more like SQL. Ideally, when working with jOOQ, you - will simply static import all methods from the Factory class: -

- import static org.jooq.impl.Factory.*; -

- This will allow to access functions even more fluently: -

- -concat(trim(FIRST_NAME), trim(LAST_NAME)); -// ... which is in fact the same as: -Factory.concat(Factory.trim(FIRST_NAME), Factory.trim(LAST_NAME)); -

- Objects created statically from the Factory do not need a reference to - any factory, as they can be constructed independently from your Configuration - (connection, dialect, schema mapping). They will access that information at - render / bind time. See - -

- -

Potential problems

-

- The jOOQ Factory expects its underlying - - to be open and ready - for - - creation. You are responsible yourself for the - lifecycle dependency between Factory and Connection. This means: -

-
    -
  • jOOQ will never close the Connection.
  • -
  • jOOQ will never commit or rollback on the Connection - (Except for CSV-imports, if explicitly configured in the )
  • -
  • jOOQ will never start any transactions.
  • -
  • - jOOQ does not know the concept of a session as for instance - Hibernate -
  • -
  • jOOQ does not know the concept of a second-level cache. SQL is - executed directly on the underlying RDBMS.
  • -
  • jOOQ does not make assumptions about the origin of the Connection. - If it is container managed, that is fine.
  • -
-

- So if you want your queries to run in separate transactions, if you - want to roll back a transaction, if you want to close a Connection and - return it to your container, you will have to take care of that - yourself. jOOQ's Factory will always expect its Connection to be in a - ready state for creating new PreparedStatements. If it is not, you have - to create a new Factory. -

-

- Please keep in mind that many jOOQ objects will reference your Factory - for their whole lifecycle. This is especially interesting, when dealing - with , - that can perform CRUD operations on the - Factory's underlying Connection. -

-
-
- - -
- Tables and Fields - -

The Table

-

Tables represent any entity in your underlying RDBMS, that holds - data for selection, insertion, updates, and deletion. In other - words, views are also considered tables by jOOQ.

-

The formal definition of a starts with

- public interface Table<R extends Record> // [...] -

- This means that every table is associated with a subtype of the - - class (see also - - ). For anonymous or ad-hoc tables, - <R> will always bind to Record itself. -

-

- Unlike in the - JPA CriteriaQuery API, - this generic type - <R> - is not given so much importance as far as - type-safety is concerned. - SQL itself is highly typesafe. You have - incredible flexibility of creating anonymous or ad-hoc - types and - reusing them from - - or from many other - use-cases. There is no way that this typesafety can be - mapped to the Java world in a convenient way. If - <R> would play a role as important - as in JPA, jOOQ would suffer from the same verbosity, or inflexibility - that JPA CriteriaQueries may have. -

- -

The Field

-

The formal definition of a Field starts with

- public interface Field<T> // [...] -

- Fields are generically parameterised with a Java type - <T> - that reflects the closest match to the RDMBS's underlying datatype for that - field. For instance, if you have a VARCHAR2 type Field in Oracle, - <T> - would bind to - - for that Field in jOOQ. Oracle's NUMBER(7) would - let - <T> - bind to - , - etc. This generic type is useful for two purposes: -

-
    -
  • It allows you to write type safe queries. For instance, you cannot - compare Field - <String> - with Field - <Integer>
  • - -
  • It - allows you to fetch correctly cast and converted values from - your database result set. This is especially useful when <T> binds - to - advanced data types, such as - - , where jOOQ - does the difficult non-standardised JDBC data type conversions for you. -
  • -
- -

Fields and tables put into action

-

The Field itself is a very broad concept. Other tools, or databases - refer to it as expression or column. When you just want to

- - SELECT 1 FROM DUAL -

- Then 1 is considered a Field or more explicitly, a - , - which implements Field, and DUAL is considered a Table or more explicitly - , which implements Table -

-

- More advanced uses become clear quickly, when you do things like -

- SELECT 1 + 1 FROM DUAL -

- Where 1 + 1 itself is a Field or more explicitly, an - - joining two Constants together. -

-

- See some details about how to create these queries in the - of the manual -

- -

TableFields

-

- A specific type of field is the - , - which represents a physical - Field in a physical Table. Both the - TableField and its referenced Table - know each other. The physical aspect - of their nature is represented in - jOOQ by - , - where every entity in your database - schema will be generated into a - corresponding Java class. -

-

- TableFields join both <R> and <T> generic parameters into their specification: -

- public interface TableField<R extends Record, T> // [...] -

- This can be used for additional type safety in the future, or by client code. -

-
-
- - -
- Results, Cursors and Records - -

The Result

-

- The - <R extends > - is essentially a wrapper for a List<R extends Record> - providing - many convenience methods for accessing single elements in - the result - set. Depending on the type of SELECT statement, - <R> can be bound - to a sub-type of Record, for instance to an - . - See the section on - - for further details. -

- -

The Cursor

-

- A similar object is the - <R extends Record>. - Unlike the Result, the cursor has not fetched all data from the database yet. - This means, you save memory (and potentially speed), but you can only access - data sequentially and you have to keep a JDBC ResultSet alive. Cursors behave - very much like the , - by providing a very simple API. Some sample methods are: -

-// Check whether there are any more records to be fetched -boolean hasNext() throws DataAccessException; - -// Fetch the next record from the underlying JDBC ResultSet -R fetchOne() throws DataAccessException; - -// Close the underlying JDBC ResultSet. Don't forget to call this, before disposing the Cursor. -void close() throws DataAccessException; - -

The Record

-

- The Record itself holds all the data from your selected tuple. If it is - a , then it corresponds exactly to the type of one of your - physical tables in your database. But any anonymous or ad-hoc tuple can - be represented by the plain Record. A record mainly provides access to - its data and adds convenience methods for data type conversion. These - are the main access ways: -

-// If you can keep a reference of the selected field, then you can get the corresponding value type-safely -<T> T getValue(Field<T> field); - -// If you know the name of the selected field within the tuple, -// then you can get its value without any type information -Object getValue(String fieldName); - -// If you know the index of the selected field within the tuple, -// then you can get its value without any type information -Object getValue(int index); -

- In some cases, you will not be able to reference the selected Fields - both when you create the SELECT statement and when you fetch data from - Records. Then you might use field names or indexes, as with JDBC. - However, of course, the type information will then be lost as well. If - you know what type you want to get, you can always use the Record's - convenience methods for type conversion, however. Some examples: -

-// These methods will try to convert a value to a BigDecimal. -// This will work for all numeric types and for CHAR/VARCHAR types, if they contain numeric values: -BigDecimal getValueAsBigDecimal(String fieldName); -BigDecimal getValueAsBigDecimal(int fieldIndex); - -// This method can perform arbitrary conversions -<T> T getValue(String fieldName, Class<? extends T> type); -<T> T getValue(int fieldIndex, Class<? extends T> type); - -

- For more information about the type conversions that are supported by - jOOQ, read the Javadoc on - -

-
-
- - -
- CRUD and Updatable Records - -

CRUD Operations with UpdatableRecords

-

- UpdatableRecords are a specific subtype of TableRecord that have - primary key information associated with them. -

-

As of jOOQ 1.5, the UpdatableRecord essentially contains three additional - methods CRUD - (Create Read Update Delete) operations:

-// Store any changes made to this record to the database. -// The record executes an INSERT if the PRIMARY KEY is NULL or has been changed. Otherwise, an UPDATE is performed. -int store(); - -// Deletes the record from the database. -int delete(); - -// Reflects changes made in the database to this Record -void refresh(); -

An example lifecycle of a book can be implemented as such:

-// Create a new record and insert it into the database -TBookRecord book = create.newRecord(T_BOOK); -book.setTitle("My first book"); -book.store(); - -// Update it with new values -book.setPublishedIn(2010); -book.store(); - -// Delete it -book.delete(); -

These operations are very simple utilities. They do not - reflect the functionality offered by Hibernate - or other persistence managers.

- -

Performing CRUD on non-updatable records

-

- If the jOOQ code-generator cannot detect any PRIMARY KEY, or UNIQUE KEY - on your tables, then the generated artefacts implement TableRecord, - instead of UpdatableRecord. A TableRecord can perform the same CRUD - operations as we have seen before, if you provide it with the necessary - key fields. The API looks like this: -

- -// INSERT or UPDATE the record using the provided keys -int storeUsing(TableField<R, ?>... keys) - -// DELETE a record using the provided keys -int deleteUsing(TableField<R, ?>... keys); - -// Reflects changes made in the database to this Record -void refreshUsing(TableField<R, ?>... keys); - -

- This is useful if your RDBMS does not support referential constraints (e.g. MySQL's - MyISAM), or if you want to - store records to an unconstrained view. An example lifecycle of a book without - any keys can then be implemented as such: -

-// Create a new record and insert it into the database -TBookRecord book = create.newRecord(T_BOOK); -book.setTitle("My first book"); -book.storeUsing(TBook.ID); - -// Update it with new values -book.setPublishedIn(2010); -book.storeUsing(TBook.ID); - -// Delete it -book.deleteUsing(TBook.ID); -
-
- - -
- The Query and its various subtypes - -

SELECT statements

-

- There are essentially two ways of creating SELECT statements in jOOQ. - For historical reasons, you can create - or - - objects and add additional query clauses, such as - or - to it. - Since jOOQ 1.3, there is also the possibility to - create SELECT statements using jOOQ's - in a much more intuitive - and SQL-like way. -

-

Use the DSL API when:

-
    -
  • You want your code to look like SQL
  • -
  • You want your IDE to help you with auto-completion (you will not be able to write select .. order by .. where .. join or any of that stuff)
  • -
-

Use the regular API when:

-
    -
  • You want to create your query step-by-step, creating query parts one-by-one
  • -
  • You need to assemble your query from various places, passing the query around, adding new conditions and joins on the way
  • -
-

In any case, all API's will construct the same underlying - implementation object, and in many cases, you can combine the two - approaches. Let's check out the various SELECT statement types:

- -
    -
  • : - This Query subtype stands for a general type of SELECT statement. - It is also the main Select type for the - . When executed, this object - will hold a . - This type is further subtyped for the various uses of a SELECT statement as such:
  • -
  • : - This Query will allow for selecting from single physical Tables only. - It therefore has access to the Table's generic type parameter - <R extends Record> and will provide a matching Result<R>. - This is especially useful if <R> is a subtype of - . - Then you will be able to perform updates on your result set immediately.
  • -
  • : - This Query will allow for selecting a subset of Fields from several - Tables. Because the results of such a query are considered of an anonymous - or ad-hoc type, this Query will bind <R> to the general type Record - itself. The purpose of this Query type is to allow for full SQL support, - including SELECT, JOIN and GROUP BY clauses.
  • -
- -

Example: SQL query and DSL query

- --- Select all books by authors born after 1920, named "Paulo" --- from a catalogue consisting of authors and books: - - -SELECT * - FROM t_author - JOIN t_book - ON t_author.id = t_book.author_id - WHERE t_author.year_of_birth > 1920 - AND t_author.first_name = 'Paulo' - ORDER BY t_book.title -// Instanciate your factory using a JDBC connection. -Factory create = new Factory(connection, SQLDialect.ORACLE); - -// Execute the query "on a single line" -Result<Record> result = create.select() - .from(T_AUTHOR) - .join(T_BOOK) - .on(T_AUTHOR.ID.equal(T_BOOK.AUTHOR_ID)) - .where(T_AUTHOR.YEAR_OF_BIRTH.greaterThan(1920) - .and(T_AUTHOR.FIRST_NAME.equal("Paulo"))) - .orderBy(T_BOOK.TITLE).fetch(); - - -

- In the above example, some generated artefacts are used for querying. - In this case, T_AUTHOR and T_BOOK are instances of types - and - respectively. - Their full qualification would read TAuthor.T_AUTHOR and TBook.T_BOOK, but in many cases, - it's useful to static import elements involved with queries, in order to decrease verbosity: - import static com.example.jooq.Tables.*; -

- -

- Apart from the singleton Table instances TAuthor.T_AUTHOR and - TBook.T_BOOK, these generated classes also contain one member - for every physical field, such as TAuthor.ID or TBook.TAUTHOR_ID, etc. - Depending on your configuration, those members can be static members - (better for static imports) or instance members (better for aliasing) -

- -
    -
  • For more information about code generation, check out the manual's section about - .
  • -
  • For more DSL examples, please consider the manual's section about the - .
  • -
- -

Example: Non-DSL query

-

- If you choose not to use the DSL API (for instance, because you don't - want to add Query parts in the order SQL expects them), you can use - this syntax: -

-// Re-use the factory to create a SelectQuery. This example will not make use of static imports... -SelectQuery q = create.selectQuery(); -q.addFrom(T_AUTHOR); - -// This example shows some "mixed" API usage, where the JOIN is added with the standard API, and the -// Condition is created using the DSL API -q.addJoin(T_BOOK, T_AUTHOR.ID.equal(T_BOOK.AUTHOR_ID)); - -// The AND operator between Conditions is implicit here -q.addConditions(T_AUTHOR.YEAR_OF_BIRTH.greaterThan(1920)); -q.addConditions(T_AUTHOR.FIRST_NAME.equal("Paulo")); -q.addOrderBy(T_BOOK.TITLE); - -

Fetching data

-

- The interface extends - , - which provides a range of methods to fetch data from the database. - Once you have constructed your SELECT query (see examples above), you - may choose to either simply execute() it, or use a variety of convenience - fetchXXX() methods. -

-

- See the manual's - - for more details. -

- - -

INSERT Statements

-

jOOQ supports two modes for INSERT statements. - The INSERT VALUES and the INSERT SELECT syntax

- -

Example: SQL query and DSL query

- -INSERT INTO T_AUTHOR - (ID, FIRST_NAME, LAST_NAME) -VALUES - (100, 'Hermann', 'Hesse'), - (101, 'Alfred', 'Döblin'); -create.insertInto(T_AUTHOR, - T_AUTHOR.ID, T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME) - .values(100, "Hermann", "Hesse") - .values(101, "Alfred", "Döblin") - .execute(); - -

The DSL syntax tries to stay close to actual SQL. In detail, - however, Java is limited in its possibilities. That's why the - .values() clause is repeated for every record in multi-record inserts. - Some RDBMS support - inserting several records at the same time. This is also supported in - jOOQ, and simulated using UNION clauses for those RDBMS that don't - support this syntax. - INSERT INTO .. SELECT .. UNION ALL SELECT .. -

-

Note: Just like in SQL itself, you can have syntax errors when you - don't have matching numbers of fields/values. Also, you can run into - runtime problems, if your field/value types don't match.

- -

Example: DSL Query, alternative syntax

-

MySQL (and some other RDBMS) allow for using an UPDATE-like syntax - for INSERT statements. This is also supported in jOOQ, should you - prefer that syntax. The above INSERT statement can also be expressed - as follows:

-create.insertInto(T_AUTHOR) - .set(T_AUTHOR.ID, 100) - .set(T_AUTHOR.FIRST_NAME, "Hermann") - .set(T_AUTHOR.LAST_NAME, "Hesse") - .newRecord() - .set(T_AUTHOR.ID, 101) - .set(T_AUTHOR.FIRST_NAME, "Alfred") - .set(T_AUTHOR.LAST_NAME, "Döblin") - .execute(); -

As you can see, this syntax is a bit more verbose, but also more - type-safe, as every field can be matched with its value.

- -

Example: ON DUPLICATE KEY UPDATE clause

-

The MySQL database supports a very convenient way to INSERT or - UPDATE a record. This is a non-standard extension to the SQL syntax, - which is supported by jOOQ and simulated in other RDBMS, where this is - possible. Here is an example how to use the ON DUPLICATE KEY UPDATE - clause:

-// Add a new author called "Koontz" with ID 3. -// If that ID is already present, update the author's name -create.insertInto(T_AUTHOR, T_AUTHOR.ID, T_AUTHOR.LAST_NAME) - .values(3, "Koontz") - .onDuplicateKeyUpdate() - .set(T_AUTHOR.LAST_NAME, "Koontz") - .execute(); - -

Example: ON DUPLICATE KEY IGNORE clause

-

The MySQL database also supports an INSERT IGNORE INTO clause. - This is supported by jOOQ using the more convenient SQL - syntax variant of ON DUPLICATE KEY IGNORE, which can be equally - simulated in other databases using a MERGE statement:

-// Add a new author called "Koontz" with ID 3. -// If that ID is already present, ignore the INSERT statement -create.insertInto(T_AUTHOR, T_AUTHOR.ID, T_AUTHOR.LAST_NAME) - .values(3, "Koontz") - .onDuplicateKeyIgnore() - .execute(); - -

Example: INSERT .. RETURNING clause

-

The Postgres database has native support for an INSERT .. RETURNING - clause. This is a very powerful concept that is simulated for all - other dialects using JDBC's - - method. Take this example:

- -// Add another author, with a generated ID -Record<?> record = -create.insertInto(T_AUTHOR, T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME) - .values("Charlotte", "Roche") - .returning(T_AUTHOR.ID) - .fetchOne(); - -System.out.println(record.getValue(T_AUTHOR.ID)); - -// For some RDBMS, this also works when inserting several values -// The following should return a 2x2 table -Result<?> result = -create.insertInto(T_AUTHOR, T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME) - .values("Johann Wolfgang", "von Goethe") - .values("Friedrich", "Schiller") - // You can request any field. Also trigger-generated values - .returning(T_AUTHOR.ID, T_AUTHOR.CREATION_DATE) - .fetch(); - -

- Be aware though, that this can lead to race-conditions - in those databases that cannot properly return generated - ID values. -

- -

Example: Non-DSL Query

-

You can always use the more verbose regular syntax of the InsertQuery, if you need more control:

-// Insert a new author into the T_AUTHOR table -InsertQuery<TAuthorRecord> i = create.insertQuery(T_AUTHOR); -i.addValue(T_AUTHOR.ID, 100); -i.addValue(T_AUTHOR.FIRST_NAME, "Hermann"); -i.addValue(T_AUTHOR.LAST_NAME, "Hesse"); - -i.newRecord(); -i.addValue(T_AUTHOR.ID, 101); -i.addValue(T_AUTHOR.FIRST_NAME, "Alfred"); -i.addValue(T_AUTHOR.LAST_NAME, "Döblin"); -i.execute(); - -

Example: INSERT Query combined with SELECT statements

-

The InsertQuery.addValue() method is overloaded, such that you can - also provide a Field, potentially containing an expression:

-// Insert a new author into the T_AUTHOR table -InsertQuery<TAuthorRecord> i = create.insertQuery(T_AUTHOR); -i.addValue(T_AUTHOR.ID, create.select(max(T_AUTHOR.ID).add(1)).from(T_AUTHOR).asField()) -i.addValue(T_AUTHOR.FIRST_NAME, "Hermann"); -i.addValue(T_AUTHOR.LAST_NAME, "Hesse"); -i.execute(); -

Note that especially MySQL (and some other RDBMS) has some - limitations regarding that syntax. You may not be able to - select from the same table you're inserting into

- -

Example: INSERT SELECT syntax support

-

In some occasions, you may prefer the INSERT SELECT syntax, for instance, when - you copy records from one table to another:

-Insert i = create.insertInto(T_AUTHOR_ARCHIVE) - .select(create.selectFrom(T_AUTHOR).where(T_AUTHOR.DECEASED.isTrue())); -i.execute(); - - -

UPDATE Statements

-

UPDATE statements are only possible on single tables. Support for - multi-table updates will be implemented in the near future.

- -

Example: SQL query and DSL query

- -UPDATE T_AUTHOR - SET FIRST_NAME = 'Hermann', - LAST_NAME = 'Hesse' - WHERE ID = 3; - -create.update(T_AUTHOR) - .set(T_AUTHOR.FIRST_NAME, "Hermann") - .set(T_AUTHOR.LAST_NAME, "Hesse") - .where(T_AUTHOR.ID.equal(3)) - .execute(); - -

Example: Non-DSL Query

-

Using the class, - this is how you could express an UPDATE statement:

-UpdateQuery<TAuthorRecord> u = create.updateQuery(T_AUTHOR); -u.addValue(T_AUTHOR.FIRST_NAME, "Hermann"); -u.addValue(T_AUTHOR.FIRST_NAME, "Hesse"); -u.addConditions(T_AUTHOR.ID.equal(3)); -u.execute(); - - -

DELETE Statements

-

DELETE statements are only possible on single tables. Support for - multi-table deletes will be implemented in the near future.

- -

Example: SQL query and DSL query

- -DELETE T_AUTHOR - WHERE ID = 100; - -create.delete(T_AUTHOR) - .where(T_AUTHOR.ID.equal(100)) - .execute(); - -

Example: Non-DSL Query

-

Using the class, - this is how you could express a DELETE statement:

-DeleteQuery<TAuthorRecord> d = create.deleteQuery(T_AUTHOR); -d.addConditions(T_AUTHOR.ID.equal(100)); -d.execute(); - - -

MERGE Statement

-

- The MERGE statement is one of the most advanced standardised SQL - constructs, which is supported by DB2, HSQLDB, Oracle, SQL Server and - Sybase (MySQL has the similar INSERT .. ON DUPLICATE KEY UPDATE - construct) -

-

- The point of the standard MERGE statement is to take a TARGET table, and - merge (INSERT, UPDATE) data from a SOURCE table into it. DB2, Oracle, - SQL Server and Sybase also allow for DELETING some data and for adding - many additional clauses. With jOOQ 2.0.1, only Oracle's MERGE extensions are supported. - Here is an example: -

- - --- Check if there is already an author called 'Hitchcock' --- If there is, rename him to John. If there isn't add him. - -MERGE INTO T_AUTHOR -USING (SELECT 1 FROM DUAL) -ON (LAST_NAME = 'Hitchcock') -WHEN MATCHED THEN UPDATE SET FIRST_NAME = 'John' -WHEN NOT MATCHED THEN INSERT (LAST_NAME) - VALUES ('Hitchcock') -create.mergeInto(T_AUTHOR) - .using(create().selectOne()) - .on(T_AUTHOR.LAST_NAME.equal("Hitchcock")) - .whenMatchedThenUpdate() - .set(T_AUTHOR.FIRST_NAME, "John") - .whenNotMatchedThenInsert(T_AUTHOR.LAST_NAME) - .values("Hitchcock") - .execute(); - - - -

MERGE Statement (H2-specific syntax)

-

- The H2 database ships with a somewhat less powerful - but a little more intuitive syntax for its own version of the MERGE statement. - An example more or less equivalent to the previous one - can be seen here: -

- --- Check if there is already an author called 'Hitchcock' --- If there is, rename him to John. If there isn't add him. - -MERGE INTO T_AUTHOR (FIRST_NAME, LAST_NAME) -KEY (LAST_NAME) -VALUES ('John', 'Hitchcock') -create.mergeInto(T_AUTHOR, - T_AUTHOR.FIRST_NAME, - T_AUTHOR.LAST_NAME) - .key(T_AUTHOR.LAST_NAME) - .values("John", "Hitchcock") - .execute(); - - -

- This syntax can be fully simulated by jOOQ for all other - databases that support the SQL standard. For more information - about the H2 MERGE syntax, see the documentation here: -
-
- http://www.h2database.com/html/grammar.html#merge -

- -

TRUNCATE Statement

-

- The syntax is trivial: -

- - - TRUNCATE TABLE T_AUTHOR; - create.truncate(T_AUTHOR).execute(); - -

This is not supported by Ingres and SQLite. jOOQ will execute a DELETE FROM - T_AUTHOR statement instead.

-
-
- - - -
- ResultQuery and fetch() methods - -

The ResultQuery and its convenience methods

-

- Data fetching is one of the great hassles in JDBC and JPA. - With jOOQ, you will be able to specify exactly, what kind of - data you want to fetch from any given query, as well as how - you want to fetch that data. This doesn't just mean distinguishing - between fetching one record at a time, or the whole resultset, - between fetching one column at a time, or the whole resultset. - This also means transforming your result (a list) into a map, - into arrays, into custom types, into JPA-annotated types, into - a call-back, or simply fetching it asynchronously -

-

These methods allow for fetching a jOOQ Result or parts of it.

- - fetch(); - -// Fetch a single field from the result - List fetch(Field field); - List fetch(int fieldIndex); - List fetch(int fieldIndex, Class type); - List fetch(String fieldName); - List fetch(String fieldName, Class type); - -// Fetch the first Record -R fetchAny(); - -// Fetch exactly one Record -R fetchOne(); - -// Fetch a single field of exactly one Record - T fetchOne(Field field); -Object fetchOne(int fieldIndex); - T fetchOne(int fieldIndex, Class type); -Object fetchOne(String fieldName); - T fetchOne(String fieldName, Class type);]]> - -

These methods transform the result into another form, if org.jooq.Result is not optimal

- -> fetchMaps(); - Map fetchOneMap(); - -// Fetch the result as a Map - Map fetchMap(Field key); - Map fetchMap(Field key, Field value); - -// Fetch the resulting records as arrays -Object[][] fetchArrays(); -Object[] fetchOneArray(); - -// Fetch a single field as an array - T[] fetchArray(Field field); -Object[] fetchArray(int fieldIndex); - T[] fetchArray(int fieldIndex, Class type); -Object[] fetchArray(String fieldName); - T[] fetchArray(String fieldName, Class type);]]> - -

These methods transform the result into a user-defined form, if org.jooq.Result is not optimal

- -true and true -// configurations to generate such POJOs with jOOQ - List fetchInto(Class type); - -// Fetch the resulting records into a custom -// record handler, similar to how Spring JdbcTemplate's -// RowMapper or the Ollin Framework works. -> H fetchInto(H handler); - -// These change the behaviour of fetching itself, -// especially, when not all data should be -// fetched at once -// ---------------------------------------------- - -// Fetch a Cursor for lazy iteration -Cursor fetchLazy(); - -// Or a JDBC ResultSet, if you prefer that -ResultSet fetchResultSet(); - -// Fetch data asynchronously and let client code -// decide, when the data must be available. -// This makes use of the java.util.concurrent API, -// Similar to how Avajé Ebean works. -FutureResult fetchLater(); -FutureResult fetchLater(ExecutorService executor);]]> -
-
- - -
- Bind values and parameters - -

Bind values

-

- Bind values are used in SQL / JDBC for various reasons. Among the most - obvious ones are: -

-
    -
  • - Protection against SQL injection. Instead of inlining values - possibly originating from user input, you bind those values to - your prepared statement and let the JDBC driver / database take - care of handling security aspects. -
  • -
  • - Increased speed. Advanced databases such as Oracle can keep - execution plans of similar queries in a dedicated cache to prevent - hard-parsing your query again and again. In many cases, the actual - value of a bind variable does not influence the execution plan, hence - it can be reused. Preparing a statement will thus be faster -
  • -
  • - On a JDBC level, you can also reuse the SQL string and prepared statement - object instead of constructing it again, as you can bind new values to - the prepared statement. This is currently not supported by jOOQ, though -
  • -
- -

Ways to introduce bind values with jOOQ

-

- Bind values are omni-present in jOOQ. Whenever you create a condition, - you're actually also adding a bind value: -

-// In jOOQ, "Poe" will be the bind value bound to the condition -LAST_NAME.equal("Poe"); - - -

- The above notation is actually convenient way to explicitly create - a bind value for "Poe". You could also write this, instead: -

-// The Factory allows for explicitly creating bind values -LAST_NAME.equal(Factory.val("Poe")); - -// Or, when static importing Factory.val: -LAST_NAME.equal(val("Poe")) - -

- Once created, bind values are part of the query's syntax tree (see - - for more information about jOOQ's internals), - and cannot be modified directly anymore. If you wish to reuse a query and - modify bind values between subsequent query executions, you can access them again - through the interface: -

- - param = query.getParam("1"); - -// You could now modify the Query's underlying bind value: -if ("Poe".equal(param.getValue())) { - param.setConverted("Orwell"); -}]]> - -

- The type can also be named explicitly - using the Factory's param() methods: -

- param1 = query.getParam("lastName"); - -// Or, keep a reference to the typed parameter in order not to lose the type information: -Param param2 = param("lastName", "Poe"); -Query query2 = create.select().from(T_AUTHOR).where(LAST_NAME.equal(param2)); - -// You can now change the bind value directly on the Param reference: -param2.setValue("Orwell"); -]]> - -

- The interface also allows for - setting new bind values directly, without accessing the Param type: -

- -Query query1 = create.select().from(T_AUTHOR).where(LAST_NAME.equal("Poe")); -query1.bind(1, "Orwell"); - -// Or, with named parameters -Query query2 = create.select().from(T_AUTHOR).where(LAST_NAME.equal(param("lastName", "Poe"))); -query2.bind("lastName", "Orwell"); - -

- NOTE: Should you wish to use jOOQ only as a query builder and execute - queries with another tool, such as Spring Data instead, you can also - use the Factory's renderNamedParams() method, to actually render named - parameter names in generated SQL: -

- - -create.renderNamedParams( - create.select() - .from(T_AUTHOR) - .where(LAST_NAME.equal( - param("lastName", "Poe")))); --- The named bind variable can be rendered - -SELECT * -FROM T_AUTHOR -WHERE LAST_NAME = :lastName - - - -

Inlining bind values

- -

- Sometimes, you may wish to avoid rendering bind - variables while still using custom values in SQL. - jOOQ refers to that as "inlined" bind values. - When bind values are inlined, they render the - actual value in SQL rather than a JDBC question mark. - Bind value inlining can be achieved in two ways: -

- -
    -
  1. - By using the settings and setting the - - to STATIC_STATEMENT. This will inline all - bind values for SQL statements rendered from - such a Factory. -
  2. -
  3. - By using Factory.inline() methods. -
  4. -
- -

- In both cases, your inlined bind values will be - properly escaped to avoid SQL syntax errors and - SQL injection. - Some examples: -

- - -
-
- - -
- QueryParts and the global architecture - -

Everything is a QueryPart

-

- A - - and all its contained objects is a - . - QueryParts essentially provide this functionality: -

-
    -
  • they can render SQL using the toSQL(RenderContext) method
  • -
  • they can bind variables using the bind(BindContext) method
  • -
- -

Both of these methods are contained in jOOQ's internal API's - , which is - internally implemented by every QueryPart. QueryPart internals are best - illustrated with an example.

- -

Example: CompareCondition

-

A simple example can be provided by checking out jOOQ's internal - representation of a - . - It is used for any condition - comparing two fields as for example the T_AUTHOR.ID = T_BOOK.AUTHOR_ID - condition here:

--- [...] -FROM T_AUTHOR -JOIN T_BOOK ON T_AUTHOR.ID = T_BOOK.AUTHOR_ID --- [...] - -

This is how jOOQ implements such a condition:

- - -

For more complex examples, please refer to the codebase, directly

-
-
- - -
- Serializability of jOOQ objects - -

Attaching QueryParts

-

- The only transient element in any jOOQ object is the - 's - underlying - . When you want to execute queries after - de-serialisation, or when you want to store/refresh/delete - , - you will have to "import" or "re-attach" them to a Factory -

-// Deserialise a SELECT statement -ObjectInputStream in = new ObjectInputStream(...); -Select<?> select = (Select<?>) in.readObject(); - -// This will throw a DetachedException: -select.execute(); - -// In order to execute the above select, attach it first -Factory create = new Factory(connection, SQLDialect.ORACLE); -create.attach(select); - - -

Automatically attaching QueryParts

-

- Note, this functionality is deprecated with jOOQ 2.1.0. - Please use the API - instead, to provide jOOQ queries with a - before - execution. -

-

In simple cases, you can register a ConfigurationProvider in jOOQ's ConfigurationRegistry

-// Create your own custom ConfigurationProvider that will make -// your default Factory available to jOOQ -ConfigurationProvider provider = new CustomConfigurationProvider(); - -// Statically register the provider to jOOQ's ConfigurationRegistry -ConfigurationRegistry.setProvider(provider); - -

Once you have executed these steps, all subsequent deserialisations - will try to access a Configuration (containing a JDBC Connection) from - your ConfigurationProvider. This may be useful when

-
    -
  • transporting jOOQ QueryParts or Records via TCP/IP, RMI, etc (e.g. - between client and server), before immediately executing queries, - storing UpdatableRecords
  • -
  • - Using automatic mechanisms as known in - Wicket -
  • -
-
-
- - -
- Extend jOOQ with custom types - -

Write your own QueryPart implementations

-

If a SQL clause is too complex to express with jOOQ, you can extend - either one of the following types for use directly in a jOOQ query:

-public abstract class CustomField<T> extends AbstractField<T> { - // [...] -} -public abstract class CustomCondition extends AbstractCondition { - // [...] -} - -

These two classes are declared public and covered by integration - tests. When you extend these classes, you will have to provide your - own implementations for the ' - bind() and - toSQL() methods:

-// This method must produce valid SQL. If your QueryPart contains other QueryParts, you may delegate SQL code generation to them -// in the correct order, passing the render context. -// -// If context.inline() is true, you must inline all bind variables -// If context.inline() is false, you must generate ? for your bind variables -public void toSQL(RenderContext context); - -// This method must bind all bind variables to a PreparedStatement. If your QueryPart contains other QueryParts, you may delegate -// variable binding to them in the correct order, passing the bind context. -// -// Every QueryPart must ensure, that it starts binding its variables at context.nextIndex(). -public void bind(BindContext context) throws DataAccessException; - -

The above contract may be a bit tricky to understand at first. The - best thing is to check out jOOQ source code and have a look at a - couple of QueryParts, to see how it's done.

-

Plain SQL as an alternative

-

If you don't need integration of rather complex QueryParts into - jOOQ, then you might be safer using simple - functionality, - where you can provide jOOQ with a simple String representation of your - embedded SQL.

-
+
+ Tutorials + + + +
+ jOOQ in 6 easy steps + +
+ +
+ A simple web application with jOOQ + +
+
- - - -
- Meta model code generation - -

Overview

-

- In the previous chapter, we have seen how to use the - in order to create - and fetch data in - . The strength of jOOQ not - only lies in its object-oriented - , - but also in the fact - that Java source code is generated from your database schema into the - META data model. jOOQ follows the paradigm, that your database comes - first (see also home page). - This means that you should not modify - generated source code, but only adapt entities in your database. Every - change in your database is reflected in a corresponding change in your - generated meta-model. -

-

- Artefacts, such as tables, views, user defined types, sequences, stored - procedures, packages have a corresponding artefact in Java. -

-
- +
+ SQL building + -
- Configuration and setup of the generator - -

The deliverables

-

- There are three binaries available with jOOQ, to be downloaded from - SourceForge - or from Maven central: -

-
    -
  • - jOOQ.jar -
    - The main library that you will include in your application to run jOOQ -
  • -
  • - jOOQ-meta.jar -
    - The utility that you will include in your build to navigate your - database schema for code generation. This can be used as a schema - crawler as well. -
  • -
  • - jOOQ-codegen.jar -
    - The utility that you will include in your build to generate your - database schema -
  • -
+
+ Factory, Configuration and Settings + -

Dependencies

-

All of jOOQ's dependencies are "optional", i.e. you can run - jOOQ without any of those libraries. - For instance, jOOQ maintains an "optional" dependency on log4j and slf4j. - This means, that jOOQ tries to find log4j (and /log4j.xml) or slf4j on the - classpath. If they are not present, then java.util.logging.Logger is - used instead. -

-

- Other optional dependencies are the JPA API, and the Oracle JDBC driver, - which is needed for Oracle's advanced data types, only -

+ +
+ SQL Dialect + +
+
+ Connection vs. DataSource + +
-

Configure jOOQ's code generator

-

You need to tell jOOQ some things about your database connection. - Here's an example of how to do it for an Oracle database

- - - - - oracle.jdbc.OracleDriver - jdbc:oracle:thin:@[your jdbc connection parameters] - [your database user] - [your database password] - - - user[db-user] - password[db-password] - - - - - - - org.jooq.util.oracle.OracleDatabase - - - .* - - - - - - [your database schema / owner / name] - - - - - - - - - [org.jooq.your.packagename] - - - [/path/to/your/dir] - - -]]> - -

- There are also lots of advanced configuration parameters, which will be - treated in the - Note, you can find the official XSD file at - http://www.jooq.org/xsd/jooq-codegen-2.1.0.xsd - for a formal specification

- -

Run jOOQ code generation

-

Code generation works by calling this class with the above property file as argument.

- org.jooq.util.GenerationTool /jooq-config.xml -

Be sure that these elements are located on the classpath:

-
    -
  • The property file
  • -
  • jooq.jar, jooq-meta.jar, jooq-codegen.jar
  • -
  • The JDBC driver you configured
  • -
- -

A command-line example (For Windows, unix/linux/etc will be similar)

-
    -
  • Put the property file, jooq*.jar and the JDBC driver into - a directory, e.g. C:\temp\jooq
  • -
  • Go to C:\temp\jooq
  • -
  • Run java -cp jooq.jar;jooq-meta.jar;jooq-codegen.jar;[JDBC-driver].jar;. org.jooq.util.GenerationTool /[property file]
  • -
-

Note that the property file must be passed as a classpath resource

- -

Run code generation from Eclipse

-

Of course, you can also run code generation from your IDE. In - Eclipse, set up a project like this. Note that this example uses - jOOQ's log4j support by adding log4j.xml and log4j.jar to the project - classpath:

-
- Eclipse configuration -
- -

Once the project is set up correctly with all required artefacts on - the classpath, you can configure an Eclipse Run Configuration for - org.jooq.util.GenerationTool.

-
- Eclipse configuration -
- -

With the properties file as an argument

-
- Eclipse configuration -
- -

And the classpath set up correctly

-
- Eclipse configuration -
- -

Finally, run the code generation and see your generated artefacts

-
- Eclipse configuration -
- -

Run generation with ant

-

- You can also use an ant task to generate your classes. As a rule of thumb, - remove the dots "." and dashes "-" from the .properties file's property names to get the - ant task's arguments: -

- - - - - - - - - - - - - - - - - -]]> - -

- Note that when running code generation with ant's <java/> task, - you may have to set fork="true": -

- - - - - [...] - - -]]> -

Integrate generation with Maven

-

Using the official jOOQ-codegen-maven plugin, you can integrate - source code generation in your Maven build process:

- - - - - org.jooq - jooq-codegen-maven - 1.6.7 - - - - - - generate - - - - - - - - postgresql - postgresql - 8.4-702.jdbc4 - - - - - - - - - org.postgresql.Driver - jdbc:postgresql:postgres - postgres - test - - - - - org.jooq.util.DefaultGenerator - - org.jooq.util.postgres.PostgresDatabase - .* - - public - - - true - false - - - org.jooq.util.maven.example - target/generated-sources/jooq - - - - -]]> -

See the full example of a pom.xml including the jOOQ-codegen artefact here: - https://github.com/jOOQ/jOOQ/blob/master/jOOQ-codegen-maven-example/pom.xml

- -

Migrate properties files from jOOQ 1.7, early versions of jOOQ 2.0.x:

-

- Before jOOQ 2.0.4, the code generator was configured using properties files - These files are still supported for source code generation, but their syntax - won't be maintained any longer. If you wish to migrate to XML, you can - migrate the file using this command on the command line -

- org.jooq.util.GenerationTool /jooq-config.properties migrate -

- Using the migrate flag, jOOQ will read the properties file and output - a corresponding XML file on system out -

- -

Use jOOQ generated classes in your application

-

Be sure, both jOOQ.jar and your generated package (see - configuration) are located on your classpath. Once this is done, you - can execute SQL statements with your generated classes.

- +
+ Custom Settings + +
+
+
+ SQL Statements + -
- Advanced generator configuration - -

Code generation

-

- In the - we have seen how jOOQ's source code generator is configured and - run within a few steps. In this chapter we'll treat some advanced - settings -

+ +
+ jOOQ's DSL and non-DSL API + +
- - - - org.jooq.util.DefaultGenerator +
+ The SELECT statement + - - - org.jooq.util.DefaultGeneratorStrategy - -]]> + +
+ The SELECT clause + +
-

- The following example shows how you can override the - DefaultGeneratorStrategy to render table and column names the way - they are defined in the database, rather than switching them to - camel case: -

+
+ The FROM clause + +
- + The JOIN clause + +
- /** - * Override this to specifiy what identifiers in Java should look like. - * This will just take the identifier as defined in the database. - */ - @Override - public String getJavaIdentifier(Definition definition) { - return definition.getOutputName(); - } +
+ The WHERE clause + +
- /** - * Override these to specify what a setter in Java should look like. Setters - * are used in TableRecords, UDTRecords, and POJOs. This example will name - * setters "set[NAME_IN_DATABASE]" - */ - @Override - public String getJavaSetterName(Definition definition, Mode mode) { - return "set" + definition.getOutputName(); - } +
+ The CONNECT BY clause + +
- /** - * Just like setters... - */ - @Override - public String getJavaGetterName(Definition definition, Mode mode) { - return "get" + definition.getOutputName(); - } +
+ The GROUP BY clause + +
- /** - * Override this method to define what a Java method generated from a database - * Definition should look like. This is used mostly for convenience methods - * when calling stored procedures and functions. This example shows how to - * set a prefix to a CamelCase version of your procedure - */ - @Override - public String getJavaMethodName(Definition definition, Mode mode) { - return "call" + org.jooq.tools.StringUtils.toCamelCase(definition.getOutputName()); - } +
+ The HAVING clause + +
- /** - * Override this method to define how your Java classes and Java files should - * be named. This example applies no custom setting and uses CamelCase versions - * instead - */ - @Override - public String getJavaClassName(Definition definition, Mode mode) { - return super.getJavaClassName(definition, mode); - } +
+ The ORDER BY clause + +
- /** - * Override this method to re-define the package names of your generated - * artefacts. - */ - @Override - public String getJavaPackageName(Definition definition, Mode mode) { - return super.getJavaPackageName(definition, mode); - } +
+ The LIMIT clause + +
- /** - * Override this method to define how Java members should be named. This is - * used for POJOs and method arguments - */ - @Override - public String getJavaMemberName(Definition definition, Mode mode) { - return definition.getOutputName(); - } +
+ The FOR UPDATE clause + +
- /** - * Override this method to define the base class for those artefacts that - * allow for custom base classes - */ - @Override - public String getJavaClassExtends(Definition definition, Mode mode) { - return Object.class.getName(); - } +
+ UNIONs, intersections, etc. + +
- /** - * Override this method to define the interfaces to be implemented by those - * artefacts that allow for custom interface implementation - */ - @Override - public List getJavaClassImplements(Definition definition, Mode mode) { - return Arrays.asList(Serializable.class.getName(), Cloneable.class.getName()); - } +
+ Oracle-style hints + +
- /** - * Override this method to define the suffix to apply to routines when - * they are overloaded. - * - * Use this to resolve compile-time conflicts in generated source code, in - * case you make heavy use of procedure overloading - */ - @Override - public String getOverloadSuffix(Definition definition, Mode mode, String overloadIndex) { - return "_OverloadIndex_" + overloadIndex; - } -}]]> +
+ Nested selects + +
+
+
-

jooq-meta configuration

-

- Within the <generator/> element, there are other configuration elements: -

+
+ The INSERT statement + +
- - - - false +
+ The UPDATE statement + +
- - true +
+ The DELETE statement + +
- - [your database schema / owner / name] +
+ The MERGE statement + +
- - - - ... - ... - - [ ... ... ] - - - - ... - - - ... - - - ... -
]]>
- -

- Check out the some of the manual's "advanced" sections - to find out more about the advanced configuration parameters. -

-
    -
  • -
  • -
  • -
- -

jooq-codegen configuration

-

Also, you can add some optional advanced configuration parameters for the generator:

- - - - - false - - - true - - - true - - - true - - - true - - - true - - - false - - - false - - - false - - - false - - - false -]]> - +
+ The TRUNCATE statement + +
+
+
+ Table expressions + -
- The schema, top-level generated artefact - -

The Schema

-

- As of jOOQ 1.5, the top-level generated object is the - . - The Schema itself has no relevant functionality, except for holding - the schema name for all dependent generated artefacts. jOOQ queries try - to always fully qualify an entity within the database using that Schema -

+ +
+ Generated Tables + +
-

- Currently, it is not possible to link generated artefacts from various - schemata. If you have a stored function from Schema A, which returns a - UDT from Schema B, the types cannot be linked. This enhancement is on - the roadmap, though: . -

+
+ Joined tables + +
-

- When you have several schemata that are logically equivalent (i.e. they - contain identical entities, but the schemata stand for different - users/customers/clients, etc), there is a solution for that. Check out - the manual's section on support for - -

+
+ Nested SELECTs + +
-

Schema contents

-

The schema can be used to dynamically discover generate database - artefacts. Tables, sequences, and other items are accessible from the - schema. For example:

-public final java.util.List<org.jooq.Sequence<?>> getSequences(); -public final java.util.List<org.jooq.Table<?>> getTables(); -
+
+ PIVOT tables + +
+ +
+ Array and cursor unnesting + +
+ +
+ The DUAL table + +
+
+
+ Column expressions + -
- Tables, views and their records - -

Tables and TableRecords

-

- The most important generated artefacts are - and - . As - discussed in previous chapters about - and - , jOOQ uses the - Table class to model entities (both tables and views) in your database - Schema. Every Table has a Record type associated with it that models a - single tuple of that entity: Table<R extends Record>. This - couple of Table<R> and R are generated as such: -

-

- Suppose we have the tables as defined in the - . - Then, using a - default configuration, these (simplified for the example) classes will - be generated: -

+ +
+ Table columns + +
-

The Table as an entity meta model

-public class TAuthor extends UpdatableTableImpl<TAuthorRecord> { +
+ Aliasing + +
- // The singleton instance of the Table - public static final TAuthor T_AUTHOR = new TAuthor(); +
+ Type casting + +
- // The Table's fields. - // Depending on your jooq-codegen configuraiton, they can also be static - public final TableField<TAuthorRecord, Integer> ID = // [...] - public final TableField<TAuthorRecord, String> FIRST_NAME = // [...] - public final TableField<TAuthorRecord, String> LAST_NAME = // [...] - public final TableField<TAuthorRecord, Date> DATE_OF_BIRTH = // [...] - public final TableField<TAuthorRecord, Integer> YEAR_OF_BIRTH = // [...] +
+ Arithmetic expressions + +
- // When you don't choose the static meta model, you can typesafely alias your tables. - // Aliased tables will then hold references to the above final fields, too - public TAuthor as(String alias) { - // [...] - } -}
+
+ Numeric functions + +
-

The Table's associated TableRecord

-

If you use the - - syntax (both in standard and DSL - mode), then your SELECT statement will return the single Table<R - extends Record>'s associated Record type <R>. In the case of - the above TAuthor Table, this will be a TAuthorRecord.

+
+ String functions + +
-public class TAuthorRecord extends UpdatableRecordImpl<TAuthorRecord> { +
+ Date and time functions + +
- // Getters and setters for the various fields - public void setId(Integer value) { // [...] - public Integer getId() { // [...] - public void setFirstName(String value) { // [...] - public String getFirstName() { // [...] - public void setLastName(String value) { // [...] - public String getLastName() { // [...] - public void setDateOfBirth(Date value) { // [...] - public Date getDateOfBirth() { // [...] +
+ System functions + +
- // Navigation methods for foreign keys - public List<TBookRecord> fetchTBooks() { // [...] -}
+
+ Aggregate functions + +
+
+ Window functions + +
-

Generated or custom POJO's instead of jOOQ's Records

-

- If you're using jOOQ along with Hibernate / JPA, or if you - want to use your own, custom domain-model instead of jOOQ's - Record type-hierarchy, you can choose to select values into - POJOs. Let's say you defined a POJO for authors: -

+
+ User-defined functions + +
- + The CASE expression + +
-import javax.persistence.Column; -import javax.persistence.Entity; +
+ Sequences and serials + +
-@Entity -public class MyAuthor { - // Some fields may be public - @Column(name = "ID") - public int id; - - // Others are private and have associated getters / setters: - private String firstName; - private String lastName; - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - @Column(name = "FIRST_NAME") - public String getFirstName() { - return firstName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - @Column(name = "LAST_NAME") - public String getLastName() { - return lastName; - } -}]]> - -

- The above could be your custom POJO or a POJO generated - by jooq-codegen (see - - for more details). Also, JPA-annotations are not necessary - if you wish to let jOOQ map record columns onto your POJO - attributes by convention. Instead of fetching records normally, - you can now let jOOQ fetch records "into" your custom type: -

- - results = create.select().from(TAuthor.T_AUTHOR).fetchInto(MyAuthor.class);]]> - -

- Read the javadoc for - Record.into() - for more details. -

- +
+ Plain SQL + +
+
+
+ Conditional expressions + -
- Procedures and packages - -

Stored procedures in modern RDBMS

-

This is one of the most important reasons why you should consider - jOOQ. Read also my - article on dzone - about why stored procedures become - more and more important in future versions of RDMBS. In this section - of the manual, we will learn how jOOQ handles stored procedures in - code generation. Especially before - was - introduced to major RDBMS, these procedures tend to have dozens of - parameters, with IN, OUT, IN OUT parameters mixed in all variations. - JDBC only knows very basic, low-level support for those constructs. - jOOQ heavily facilitates the use of stored procedures and functions - via its source code generation. Essentially, it comes down to this: -

+ +
+ Condition building + +
-

"Standalone" stored procedures and functions

-

Let's say you have these stored procedures and functions in your Oracle database

--- Check whether there is an author in T_AUTHOR by that name -CREATE OR REPLACE FUNCTION f_author_exists (author_name VARCHAR2) RETURN NUMBER; +
+ AND, OR boolean operators + +
--- Check whether there is an author in T_AUTHOR by that name -CREATE OR REPLACE PROCEDURE p_author_exists (author_name VARCHAR2, result OUT NUMBER); +
+ Comparison predicate + +
--- Check whether there is an author in T_AUTHOR by that name and get his ID -CREATE OR REPLACE PROCEDURE p_author_exists_2 (author_name VARCHAR2, result OUT NUMBER, id OUT NUMBER);
+
+ BETWEEN predicate + +
-

jOOQ will essentially generate two artefacts for every procedure/function:

-
    -
  • A class holding a formal Java representation of the procedure/function
  • -
  • Some convenience methods to facilitate calling that procedure/function
  • -
-

Let's see what these things look like, in Java. The classes (simplified for the example):

+
+ LIKE predicate + +
-// The function has a generic type parameter <T> bound to its return value -public class FAuthorExists extends org.jooq.impl.AbstractRoutine<BigDecimal> { +
+ IN predicate + +
- // Much like Tables, functions have static parameter definitions - public static final Parameter<String> AUTHOR_NAME = // [...] - - // And much like TableRecords, they have setters for their parameters - public void setAuthorName(String value) { // [...] - public void setAuthorName(Field<String> value) { // [...] -} - -public class PAuthorExists extends org.jooq.impl.AbstractRoutine<java.lang.Void> { - - // In procedures, IN, OUT, IN OUT parameters are all represented - // as static parameter definitions as well - public static final Parameter<String> AUTHOR_NAME = // [...] - public static final Parameter<BigDecimal> RESULT = // [...] - - // IN and IN OUT parameters have generated setters - public void setAuthorName(String value) { // [...] - - // OUT and IN OUT parameters have generated getters - public BigDecimal getResult() { // [...] -} - -public class PAuthorExists_2 extends org.jooq.impl.AbstractRoutine<java.lang.Void> { - public static final Parameter<String> AUTHOR_NAME = // [...] - public static final Parameter<BigDecimal> RESULT = // [...] - public static final Parameter<BigDecimal> ID = // [...] - - // the setters... - public void setAuthorName(String value) { // [...] - - // the getters... - public BigDecimal getResult() { // [...] - public BigDecimal getId() { // [...] -}
- -

An example invocation of such a stored procedure might look like this:

- -PAuthorExists p = new PAuthorExists(); -p.setAuthorName("Paulo"); -p.execute(configuration); -assertEquals(BigDecimal.ONE, p.getResult()); - -

- The above configuration is a - , - holding a reference to a JDBC connection, as discussed in a previous section. - - If you use the generated convenience methods, however, things are much simpler, still: -

-// Every schema has a single Routines class with convenience methods -public final class Routines { - - // Convenience method to directly call the stored function - public static BigDecimal fAuthorExists(Configuration configuration, String authorName) { // [...] - - // Convenience methods to transform the stored function into a - // Field<BigDecimal>, such that it can be used in SQL - public static Field<BigDecimal> fAuthorExists(Field<String> authorName) { // [...] - public static Field<BigDecimal> fAuthorExists(String authorName) { // [...] - - // Procedures with 0 OUT parameters create void methods - // Procedures with 1 OUT parameter create methods as such: - public static BigDecimal pAuthorExists(Configuration configuration, String authorName) { // [...] - - // Procedures with more than 1 OUT parameter return the procedure - // object (see above example) - public static PAuthorExists_2 pAuthorExists_2(Configuration configuration, String authorName) { // [...] -} - -

An sample invocation, equivalent to the previous example:

-assertEquals(BigDecimal.ONE, Procedures.pAuthorExists(configuration, "Paulo")); - - -

jOOQ's understanding of procedures vs functions

-

- jOOQ does not formally distinguish procedures from functions. - jOOQ only knows about routines, which can have return values - and/or OUT parameters. This is the best option to handle the - variety of stored procedure / function support across the - various supported RDBMS. For more details, read on about this - topic, here: -

-

- blog.jooq.org/2011/10/17/what-are-procedures-and-functions-after-all/ -

- -

Packages in Oracle

-

- Oracle uses the concept of a PACKAGE to group several - procedures/functions into a sort of namespace. The - SQL standard - talks about "modules", to represent this concept, even if this is - rarely implemented. This is reflected in jOOQ by the use of Java - sub-packages in the source code generation destination package. Every - Oracle package will be reflected by -

-
    -
  • A Java package holding classes for formal Java representations of - the procedure/function in that package -
  • -
  • A Java class holding convenience methods to facilitate calling - those procedures/functions -
  • -
-

- Apart from this, the generated source code looks exactly like the - one for - standalone procedures/functions. -

- -

Member functions and procedures in Oracle

-

- Oracle UDT's can have object-oriented structures including member functions - and procedures. With Oracle, you can do things like this: -

-CREATE OR REPLACE TYPE u_author_type AS OBJECT ( - id NUMBER(7), - first_name VARCHAR2(50), - last_name VARCHAR2(50), - - MEMBER PROCEDURE LOAD, - MEMBER FUNCTION count_books RETURN NUMBER -) - --- The type body is omitted for the example - - -

- These member functions and procedures can simply be mapped to Java - methods: -

- - -// Create an empty, attached UDT record from the Factory -UAuthorType author = create.newRecord(U_AUTHOR_TYPE); - -// Set the author ID and load the record using the LOAD procedure -author.setId(1); -author.load(); - -// The record is now updated with the LOAD implementation's content -assertNotNull(author.getFirstName()); -assertNotNull(author.getLastName()); - -

For more details about UDT's see the Manual's section on -

- -
+
+ EXISTS predicate + +
+
+
+ Bind values and parameters + -
- UDT's including ARRAY and ENUM types - -

Increased RDBMS support for UDT's

-

- In recent years, most RDBMS have started to implement some support for - advanced data types. This support has not been adopted very well by - database users in the Java world, for several reasons: -

-
    -
  • They are usually orthogonal to relational concepts. It is not easy - to modify a UDT once it is referenced by a table column.
  • -
  • There is little standard support of accessing them from JDBC (and - probably other database connectivity standards).
  • -
-

- On the other hand, especially with stored procedures, these data types - are likely to become more and more useful in the future. If you have a - look at Postgres' capabilities of dealing with advanced data types - (ENUMs, - ARRAYs, - UDT's), - this becomes more and more obvious. -

-

It is a central strategy for jOOQ, to standardise access to these - kinds of types (as well as to - , of course) across all - RDBMS, where these types are supported.

+ +
+ Indexed parameters + +
-

UDT types

-

User Defined Types (UDT) are helpful in major RDMBS with lots - of proprietary functionality. The biggest player is clearly Oracle. - Currently, jOOQ provides UDT support for only two databases:

-
    -
  • Oracle
  • -
  • Postgres
  • -
-

Apart from that,

-
    -
  • - DB2 UDT's are not supported as they are very tough to - serialise/deserialise. We don't think that this is a big enough - requirement to put more effort in those, right now (see also the - developers' discussion on - ) -
  • -
+
+ Named parameters + +
-

In Oracle, you would define UDTs like this:

-CREATE TYPE u_street_type AS OBJECT ( - street VARCHAR2(100), - no VARCHAR2(30) -) +
+ Inlined parameters + +
-CREATE TYPE u_address_type AS OBJECT ( - street u_street_type, - zip VARCHAR2(50), - city VARCHAR2(50), - country VARCHAR2(50), - since DATE, - code NUMBER(7) -)
- -

These types could then be used in tables and/or stored procedures like such:

-CREATE TABLE t_author ( - id NUMBER(7) NOT NULL PRIMARY KEY, - -- [...] - address u_address_type -) - -CREATE OR REPLACE PROCEDURE p_check_address (address IN OUT u_address_type); - -

- Standard JDBC UDT support encourages JDBC-driver developers to implement - interfaces such as - , - and - . - Those interfaces are non-trivial to implement, or - to hook into. Also access to - - is not really simple. Due - to the lack of a well-defined JDBC standard, Oracle's JDBC driver - rolls their own proprietary methods of dealing with these types. jOOQ - goes a different way, it hides those facts from you entirely. With - jOOQ, the above UDT's will be generated in simple - and - as such: -

-// There is an analogy between UDT/Table and UDTRecord/TableRecord... -public class UAddressType extends UDTImpl<UAddressTypeRecord> { - - // The UDT meta-model singleton instance - public static final UAddressType U_ADDRESS_TYPE = new UAddressType(); - - // UDT attributes are modeled as static members. Nested UDT's - // behave similarly - public static final UDTField<UAddressTypeRecord, UStreetTypeRecord> STREET = // [...] - public static final UDTField<UAddressTypeRecord, String> ZIP = // [...] - public static final UDTField<UAddressTypeRecord, String> CITY = // [...] - public static final UDTField<UAddressTypeRecord, String> COUNTRY = // [...] - public static final UDTField<UAddressTypeRecord, Date> SINCE = // [...] - public static final UDTField<UAddressTypeRecord, Integer> CODE = // [...] -} - -

Now, when you interact with entities or procedures that hold UDT's, that's very simple as well. Here is an example:

-// Fetch any author from the T_AUTHOR table -TAuthorRecord author = create.selectFrom(T_AUTHOR).fetchAny(); - -// Print out the author's address's house number -System.out.println(author.getAddress().getStreet().getNo()); - -

A similar thing can be achieved when interacting with the example stored procedure:

-// Create a new UDTRecord of type U_ADDRESS_TYPE -UAddressTypeRecord address = new UAddressTypeRecord(); -address.setCountry("Switzerland"); - -// Call the stored procedure with IN OUT parameter of type U_ADDRESS_TYPE -address = Procedures.pCheckAddress(connection, address); - - -

ARRAY types

-

- The notion of ARRAY types in RDBMS is not standardised at all. Very - modern databases (especially the Java-based ones) have implemented - ARRAY types exactly as what they are. "ARRAYs of something". In other - words, an ARRAY OF VARCHAR would be something very similar to Java's - notion of String[]. An ARRAY OF ARRAY OF VARCHAR would then be a - String[][] in Java. Some RDMBS, however, enforce stronger typing and - need the explicit creation of types for every ARRAY as well. These are - example String[] ARRAY types in various SQL dialects supported by jOOQ - 1.5.4: -

-
    -
  • Oracle: VARRAY OF VARCHAR2. A strongly typed object encapsulating an ARRAY of a given type. See the documentation.
  • -
  • Postgres: text[]. Any data type can be turned into an array by suffixing it with []. See the documentation
  • -
  • HSQLDB: VARCHAR ARRAY. Any data type can be turned into an array by suffixing it with ARRAY. See the documentation
  • -
  • H2: ARRAY. H2 does not know of typed arrays. All ARRAYs are mapped to Object[]. See the documentation
  • -
-

Soon to be supported:

-
    -
  • DB2: Knows a similar strongly-typed ARRAY type, like Oracle
  • -
-

- From jOOQ's perspective, the ARRAY types fit in just like any other - type wherever the - <T> generic type parameter is existent. It integrates well with tables - and stored procedures. -

- -

Example: General ARRAY types

-

An example usage of ARRAYs is given here for the Postgres dialect

- -CREATE TABLE t_arrays ( - id integer not null primary key, - string_array VARCHAR(20)[], - number_array INTEGER[] -) - -CREATE FUNCTION f_arrays(in_array IN text[]) RETURNS text[] - -

When generating source code from the above entities, these artefacts will be created in Java:

-public class TArrays extends UpdatableTableImpl<TArraysRecord> { - - // The generic type parameter <T> is bound to an array of a matching type - public static final TableField<TArraysRecord, String[]> STRING_ARRAY = // [...] - public static final TableField<TArraysRecord, Integer[]> NUMBER_ARRAY = // [...] -} - -// The convenience class is enhanced with these methods -public final class Functions { - public static String[] fArrays(Connection connection, String[] inArray) { // [...] - public static Field<String[]> fArrays(String[] inArray) { // [...] - public static Field<String[]> fArrays(Field<String[]> inArray) { // [...] -} - -

Example: Oracle VARRAY types

-

In Oracle, a VARRAY type is something slightly different than in - other RDMBS. It is a type that encapsules the actual ARRAY and creates - a new type from it. While all text[] types are equal and thus - compatible in Postgres, this does not apply for all VARRAY OF VARCHAR2 - types. Hence, it is important to provide access to VARRAY types and - generated objects from those types as well. The example above would - read like this in Oracle:

- -CREATE TYPE u_string_array AS VARRAY(4) OF VARCHAR2(20) -CREATE TYPE u_number_array AS VARRAY(4) OF NUMBER(7) - -CREATE TABLE t_arrays ( - id NUMBER(7) not null primary key, - string_array u_string_array, - number_array u_number_array -) - -CREATE OR REPLACE FUNCTION f_arrays (in_array u_string_array) -RETURN u_string_array - -

Note that it becomes clear immediately, that a mapping from - U_STRING_ARRAY to String[] is obvious. But a mapping from String[] to - U_STRING_ARRAY is not. These are the generated - and other - artefacts in Oracle:

- -public class UStringArrayRecord extends ArrayRecordImpl<String> { // [...] -public class UNumberArrayRecord extends ArrayRecordImpl<Integer> { // [...] - -public class TArrays extends UpdatableTableImpl<TArraysRecord> { - public static final TableField<TArraysRecord, UStringArrayRecord> STRING_ARRAY = // [...] - public static final TableField<TArraysRecord, UNumberArrayRecord> NUMBER_ARRAY = // [...] -} - -public final class Functions { - public static UStringArrayRecord fArrays3(Connection connection, UStringArrayRecord inArray) { // [...] - public static Field<UStringArrayRecord> fArrays3(UStringArrayRecord inArray) { // [...] - public static Field<UStringArrayRecord> fArrays3(Field<UStringArrayRecord> inArray) { // [...] -} - - -

ENUM types

-

True ENUM types are a rare species in the RDBMS world. Currently, - MySQL and Postgres are the only RDMBS supported by jOOQ, that provide - ENUM types.

- -
    -
  • In MySQL, an ENUM type is declared directly upon a column. It cannot be reused as a type. See the documentation.
  • -
  • In Postgres, the ENUM type is declared independently and can be reused among tables, functions, etc. See the documentation.
  • -
  • Other RDMBS know about "ENUM constraints", such as the Oracle CHECK constraint. These are not true ENUMS, however. jOOQ refrains from using their information for source code generation
  • -
- -

Some examples:

--- An example enum type -CREATE TYPE u_book_status AS ENUM ('SOLD OUT', 'ON STOCK', 'ORDERED') - --- An example useage of that enum type -CREATE TABLE t_book ( - id INTEGER NOT NULL PRIMARY KEY, - - -- [...] - status u_book_status -) - -

The above Postgres ENUM type will be generated as

-public enum UBookStatus implements EnumType { - ORDERED("ORDERED"), - ON_STOCK("ON STOCK"), - SOLD_OUT("SOLD OUT"); - - // [...] -} -

Intuitively, the generated classes for the T_BOOK table in Postgres would look like this:

-// The meta-model class -public class TBook extends UpdatableTableImpl<TBookRecord> { - - // The TableField STATUS binds <T> to UBookStatus - public static final TableField<TBookRecord, UBookStatus> STATUS = // [...] - - // [...] -} - -// The record class -public class TBookRecord extends UpdatableRecordImpl<TBookRecord> { - - // Corresponding to the Table meta-model, also setters and getters - // deal with the generated UBookStatus - public void setStatus(UBookStatus value) { // [...] - public UBookStatus getStatus() { // [...] -} - -

Note that jOOQ allows you to simulate ENUM types where this makes - sense in your data model. See the section on - for more - details.

-
+
+ SQL injection and plain SQL QueryParts + +
+
+
+ QueryParts + -
- Sequences and Serials - -

Sequences as a source for identity values

-

Sequences implement the - interface, providing essentially this functionality:

+ +
+ jOOQ architecture + +
-// Get a field for the CURRVAL sequence property -Field<T> currval(); +
+ Custom QueryParts + +
-// Get a field for the NEXTVAL sequence property -Field<T> nextval();
-

So if you have a sequence like this in Oracle:

- CREATE SEQUENCE s_author_id -

This is what jOOQ will generate:

-public final class Sequences { +
+ Plain SQL QueryParts + +
- // A static sequence instance - public static final Sequence<BigInteger> S_AUTHOR_ID = // [...] -}
- -

Which you can use in a select statement as such:

-Field<BigInteger> s = Sequences.S_AUTHOR_ID.nextval(); -BigInteger nextID = create.select(s).fetchOne(s); - -

Or directly fetch currval() and nextval() from the sequence using the Factory:

-BigInteger currval = create.currval(Sequences.S_AUTHOR_ID); -BigInteger nextval = create.nextval(Sequences.S_AUTHOR_ID); -
+
+ Serializability + +
+
- - - -
- DSL or fluent API. Where SQL meets Java - -

Overview

-

jOOQ ships with its own DSL (or - Domain Specific Language) that - simulates SQL as good as possible in Java. This means, that you can - write SQL statements almost as if Java natively supported that syntax - just like .NET's C# does with LINQ to SQL.

- -

Here is an example to show you what that means. When you want to write a query like this in SQL:

- --- Select all books by authors born after 1920, --- named "Paulo" from a catalogue: -SELECT * - FROM t_author a - JOIN t_book b ON a.id = b.author_id - WHERE a.year_of_birth > 1920 - AND a.first_name = 'Paulo' - ORDER BY b.title -Result<Record> result = -create.select() - .from(T_AUTHOR.as("a")) - .join(T_BOOK.as("b")).on(a.ID.equal(b.AUTHOR_ID)) - .where(a.YEAR_OF_BIRTH.greaterThan(1920) - .and(a.FIRST_NAME.equal("Paulo"))) - .orderBy(b.TITLE) - .fetch(); - -

- You couldn't come much closer to SQL itself in Java, without re-writing the compiler. - We'll see how the aliasing works later in the section about - -

-
- +
+ Code generation + -
- Complete SELECT syntax - -

SELECT from anonymous or ad-hoc types

-

When you don't just perform CRUD (i.e. SELECT * FROM your_table WHERE ID = ?), - you're usually generating new types using custom projections. With jOOQ, this is - as intuitive, as if using SQL directly. A more or less complete example of the "standard" SQL syntax, plus - some extensions, is provided by a query like this: -

- --- get all authors' first and last names, and the number --- of books they've written in German, if they have written --- more than five books in German in the last three years --- (from 2011), and sort those authors by last names --- limiting results to the second and third row, locking --- the rows for a subsequent update... whew! - - SELECT T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, COUNT(*) - FROM T_AUTHOR - JOIN T_BOOK ON T_AUTHOR.ID = T_BOOK.AUTHOR_ID - WHERE T_BOOK.LANGUAGE = 'DE' - AND T_BOOK.PUBLISHED > '2008-01-01' -GROUP BY T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME - HAVING COUNT(*) > 5 -ORDER BY T_AUTHOR.LAST_NAME ASC NULLS FIRST - LIMIT 2 - OFFSET 1 - FOR UPDATE - -

So that's daily business. How to do it with jOOQ: When you first create a SELECT statement using the Factory's select() methods

-SelectFromStep select(Field<?>... fields); - -// Example: -create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()); - -

- jOOQ will return an "intermediary" type to you, representing the - SELECT statement about to be created (by the way, check out the - section on - to learn more about the COUNT(*) - function). This type is the - . - When you have a reference - to this type, you may add a FROM clause, although that clause is - optional. This is reflected by the fact, that the SelectFromStep type - extends - , - which allows for adding the subsequent - clauses. Let's say you do decide to add a FROM clause, then you can - use this method for instance: -

-SelectJoinStep from(TableLike<?>... table); - -// The example, continued: -create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) - .from(T_AUTHOR); - -

After adding the table-like structures (mostly just Tables) to - select from, you may optionally choose to add a JOIN clause, as the - type returned by jOOQ is the step where you can add JOINs. Again, - adding these clauses is optional, as the - extends - . - But let's say we add a JOIN:

-// These join types are supported -SelectOnStep join(Table<?> table); -SelectOnStep leftOuterJoin(Table<?> table); -SelectOnStep rightOuterJoin(Table<?> table); -SelectOnStep fullOuterJoin(Table<?> table); -SelectJoinStep crossJoin(Table<?> table); -SelectJoinStep naturalJoin(Table<?> table); -SelectJoinStep naturalLeftOuterJoin(Table<?> table); -SelectJoinStep naturalRightOuterJoin(Table<?> table); - -// The example, continued: -create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) - .from(T_AUTHOR) - .join(T_BOOK); - -

Now, if you do add a JOIN clause, you have to specify the JOIN .. ON - condition before you can add more clauses. That's not an optional step - for some JOIN types. This is reflected by the fact that - - is a top-level interface.

- -... keyFields); -SelectJoinStep onKey(ForeignKey key); -SelectJoinStep using(Field... fields); - -// The example, continued: -create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) - .from(T_AUTHOR) - .join(T_BOOK).on(T_BOOK.AUTHOR_ID.equal(T_AUTHOR.ID));]]> - -

- See the section about - - to learn more about the many ways - to create Conditions in jOOQ. - See also the section about - - to learn more about the various ways of creating JOIN - expressions -

-

- Now we're half way through. As you can - see above, we're back to the SelectJoinStep. This means, we can - re-iterate and add another JOIN clause, just like in SQL. Or we go on - to the next step, adding conditions in the - :

-SelectConditionStep where(Condition... conditions); - -// The example, continued: -create.select(TAuthor.FIRST_NAME, TAuthor.LAST_NAME, count()) - .from(T_AUTHOR) - .join(T_BOOK).on(T_BOOK.AUTHOR_ID.equal(T_AUTHOR.ID)) - .where(T_BOOK.LANGUAGE.equal("DE")); - -

Now the returned type - is a special one, where - you can add more conditions to the already existing WHERE clause. - Every time you add a condition, you will return to that - SelectConditionStep, as the number of additional conditions is - unlimited. Note that of course you can also just add a single combined - condition, if that is more readable or suitable for your use-case. - Here's how we add another condition:

-SelectConditionStep and(Condition condition); - -// The example, continued: -create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) - .from(T_AUTHOR) - .join(T_BOOK).on(T_BOOK.AUTHOR_ID.equal(T_AUTHOR.ID)) - .where(T_BOOK.LANGUAGE.equal("DE")) - .and(T_BOOK.PUBLISHED.greaterThan(parseDate('2008-01-01'))); - -

Let's assume we have that method parseDate() creating a - for us. - Then we'll continue adding the GROUP BY clause -

-SelectHavingStep groupBy(Field<?>... fields); - -// The example, continued: -create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) - .from(T_AUTHOR) - .join(T_BOOK).on(T_BOOK.AUTHOR_ID.equal(T_AUTHOR.ID)) - .where(T_BOOK.LANGUAGE.equal("DE")) - .and(T_BOOK.PUBLISHED.greaterThan(parseDate('2008-01-01'))) - .groupBy(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME); - -

and the HAVING clause:

-SelectOrderByStep having(Condition... conditions); - -// The example, continued: -create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) - .from(T_AUTHOR) - .join(T_BOOK).on(T_BOOK.AUTHOR_ID.equal(T_AUTHOR.ID)) - .where(T_BOOK.LANGUAGE.equal("DE")) - .and(T_BOOK.PUBLISHED.greaterThan(parseDate('2008-01-01'))) - .groupBy(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME) - .having(count().greaterThan(5)); - -

and the ORDER BY clause. Some RDBMS support NULLS FIRST and NULLS - LAST extensions to the ORDER BY clause. If this is not supported by - the RDBMS, then the behaviour is simulated with an additional CASE - WHEN ... IS NULL THEN 1 ELSE 0 END clause.

-SelectLimitStep orderBy(Field<?>... fields); - -// The example, continued: -create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) - .from(T_AUTHOR) - .join(T_BOOK).on(T_BOOK.AUTHOR_ID.equal(T_AUTHOR.ID)) - .where(T_BOOK.LANGUAGE.equal("DE")) - .and(T_BOOK.PUBLISHED.greaterThan(parseDate('2008-01-01'))) - .groupBy(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME) - .having(count().greaterThan(5)) - .orderBy(T_AUTHOR.LAST_NAME.asc().nullsFirst()); - -

and finally the LIMIT clause. Most dialects have a means of limiting - the number of result records (except Oracle). Some even support having - an OFFSET to the LIMIT clause. Even if your RDBMS does not support the - full LIMIT ... OFFSET ... (or TOP ... START AT ..., or FETCH FIRST ... ROWS ONLY, etc) - clause, jOOQ will simulate the LIMIT clause using nested selects and filtering on - ROWNUM (for Oracle), or on ROW_NUMBER() (for DB2 and SQL - Server):

-SelectFinalStep limit(int offset, int numberOfRows); - -// The example, continued: -create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) - .from(T_AUTHOR) - .join(T_BOOK).on(T_BOOK.AUTHOR_ID.equal(T_AUTHOR.ID)) - .where(T_BOOK.LANGUAGE.equal("DE")) - .and(T_BOOK.PUBLISHED.greaterThan(parseDate('2008-01-01'))) - .groupBy(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME) - .having(count().greaterThan(5)) - .orderBy(T_AUTHOR.LAST_NAME.asc().nullsFirst()) - .limit(1, 2); - -

In the final step, there are some proprietary extensions available - only in some RDBMS. One of those extensions are the FOR UPDATE - (supported in most RDBMS) and FOR SHARE clauses (supported only in - MySQL and Postgres):

-SelectFinalStep forUpdate(); - -// The example, continued: -create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) - .from(T_AUTHOR) - .join(T_BOOK).on(T_BOOK.AUTHOR_ID.equal(T_AUTHOR.ID)) - .where(T_BOOK.LANGUAGE.equal("DE")) - .and(T_BOOK.PUBLISHED.greaterThan(parseDate('2008-01-01'))) - .groupBy(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME) - .having(count().greaterThan(5)) - .orderBy(T_AUTHOR.LAST_NAME.asc().nullsFirst()) - .limit(1, 2) - .forUpdate(); - -

- Now the most relevant super-type of the object we have just created is - . - This type can be reused in various expressions such as in the - , - , - etc. If you just want to execute this select - statement, you can choose any of these methods as discussed in the - section about the : -

- -// Just execute the query. -int execute(); - -// Execute the query and retrieve the results -Result<Record> fetch(); - -// Execute the query and retrieve the first Record -Record fetchAny(); - -// Execute the query and retrieve the single Record -// An Exception is thrown if more records were available -Record fetchOne(); - -// [...] - - -

SELECT from single physical tables

-

A very similar, but limited API is available, if you want to select from single - physical tables in order to retrieve TableRecords or even - UpdatableRecords (see also the manual's section on - ). - The decision, which type of select to create is - already made at the very first step, when you create the SELECT - statement with the Factory:

- - public <R extends Record> SimpleSelectWhereStep<R> selectFrom(Table<R> table); -

As you can see, there is no way to further restrict/project the selected - fields. This just selects all known TableFields in the supplied Table, - and it also binds <R extends Record> to your Table's associated - Record. An example of such a Query would then be:

-TBook book = create.selectFrom(T_BOOK) - .where(TBook.LANGUAGE.equal("DE")) - .orderBy(TBook.TITLE) - .fetchAny(); -
+
+ Configuration +
- -
- Table sources - -

Create complex and nested table sources

-

- In the relational data model, - there are many operations performed on entities, i.e. tables in order to join them together - before applying predicates, renaming operations and projections. Apart from the convenience - methods for joining table sources in the - , - the type itself provides a - rich API for creating joined table sources. See an extract of the Table API: -

- table); -TableOnStep join(String sql); -TableOnStep join(String sql, Object... bindings); - -// All other JOIN types are equally overloaded with "String sql" convenience methods... -TableOnStep leftOuterJoin(TableLike table); -TableOnStep rightOuterJoin(TableLike table); -TableOnStep fullOuterJoin(TableLike table); - -// These JOIN types don't take any additional clause -Table crossJoin(TableLike table); -Table naturalJoin(TableLike table); -Table naturalLeftOuterJoin(TableLike table); -Table naturalRightOuterJoin(TableLike table); - -// Oracle and SQL Server also know PIVOT / UNPIVOT clauses for transforming a -// table into another one using a list of PIVOT values -PivotForStep pivot(Field... aggregateFunctions); -PivotForStep pivot(Collection> aggregateFunctions); - -// Relational division can be applied to a table, transforming it into a -// "quotient" using an intuitive syntax -DivideByOnStep divideBy(Table divisor);]]> - -

- The type - contains methods for constructing the ON / ON KEY / USING clauses -

- - using(Field... fields); -Table using(Collection> fields); - -// The ON KEY clause is a "synthetic" clause that does not exist in any SQL dialect. jOOQ usually has all -// foreign key relationship information to dynamically render "ON [ condition ... ]" clauses -TableOnConditionStep onKey() throws DataAccessException; -TableOnConditionStep onKey(TableField... keyFields) throws DataAccessException; -TableOnConditionStep onKey(ForeignKey key);]]> - -
    -
  • - For more details about the PIVOT clause, see the - -
  • -
  • - For more details about the DIVIDE BY clause, see the - -
  • -
-
+
+ Advanced Configuration +
- -
- Conditions - -

Conditions are the SELECT's core business

-

In your average application, you will typically have 3-4 SQL queries - that have quite a long list of predicates (and possibly JOINs), such - that you start to lose track over the overall boolean expression that - you're trying to apply.

-

In jOOQ, most Conditions can be created and combined almost as - easily as in SQL itself. The two main participants for creating - Conditions are the , - which is typically a participant of a - condition, and the - itself:

-public interface Condition { - Condition and(Condition other); - Condition and(String sql); - Condition and(String sql, Object... bindings); - Condition andNot(Condition other); - Condition andExists(Select<?> select); - Condition andNotExists(Select<?> select); - Condition or(Condition other); - Condition or(String sql); - Condition or(String sql, Object... bindings); - Condition orNot(Condition other); - Condition orExists(Select<?> select); - Condition orNotExists(Select<?> select); - Condition not(); -} - -

The above example describes the essence of boolean logic in jOOQ. As - soon as you have a Condition object, you can connect that to other - Conditions, which will then give you a combined condition with exactly - the same properties. There are also convenience methods to create an - EXISTS clause and connect it to an existing condition. In order to - create a new Condition you are going to depart from a Field in most - cases. Here are some important API elements in the Field interface: -

- - { - Condition isNull(); - Condition isNotNull(); - Condition like(T value); - Condition likeIgnoreCase(T value); - Condition notLike(T value); - Condition notLikeIgnoreCase(T value); - Condition in(T... values); - Condition in(Select query); - Condition notIn(Collection values); - Condition notIn(T... values); - Condition notIn(Select query); - Condition in(Collection values); - Condition between(T minValue, T maxValue); - Condition contains(T value); - Condition contains(Field value); - Condition equal(T value); - Condition equal(Field field); - Condition equal(Select query); - Condition equalAny(Select query); - Condition equalAny(T... array); - Condition equalAny(Field array); - Condition equalAll(Select query); - Condition equalAll(T... array); - Condition equalAll(Field array); - Condition equalIgnoreCase(String value); - Condition equalIgnoreCase(Field value); - Condition notEqual(T value); - Condition notEqual(Field field); - Condition notEqual(Select query); - Condition notEqualAny(Select query); - Condition notEqualAny(T... array); - Condition notEqualAny(Field array); - Condition notEqualAll(Select query); - Condition notEqualAll(T... array); - Condition notEqualAll(Field array); - - // Subselects, ANY and ALL quantifiers are also supported for these: - Condition lessThan(T value); - Condition lessOrEqual(T value); - Condition greaterThan(T value); - Condition greaterOrEqual(T value); -}]]> - -

As you see in the partially displayed API above, you can compare a - Field either with other Fields, with constant values (which is a - shortcut for calling Factory.val(T value)), or with a nested SELECT - statement. See some more - .

-

Combining the API of Field and Condition you can express complex predicates like this:

- -(T_BOOK.TYPE_CODE IN (1, 2, 5, 8, 13, 21) AND T_BOOK.LANGUAGE = 'DE') OR -(T_BOOK.TYPE_CODE IN (2, 3, 5, 7, 11, 13) AND T_BOOK.LANGUAGE = 'FR') OR -(T_BOOK.TYPE_CODE IN (SELECT CODE FROM T_TYPES) AND T_BOOK.LANGUAGE = 'EN') - -

Just write:

-T_BOOK.TYPE_CODE.in(1, 2, 5, 8, 13, 21) .and(T_BOOK.LANGUAGE.equal("DE")).or( -T_BOOK.TYPE_CODE.in(2, 3, 5, 7, 11, 13) .and(T_BOOK.LANGUAGE.equal("FR")).or( -T_BOOK.TYPE_CODE.in(create.select(T_TYPES.CODE).from(T_TYPES)).and(T_BOOK.LANGUAGE.equal("EN")))); -
-
- - -
- Aliased tables and fields - -

Aliasing Tables

-

A typical example of what you might want to do in SQL is this:

-SELECT a.ID, b.ID - FROM T_AUTHOR a - JOIN T_BOOK b on a.ID = b.AUTHOR_ID - -

- In this example, we are aliasing Tables, calling them a and b. - The way aliasing works depends on how you generate your meta model - using jooq-codegen (see the manual's section about - ). Things become - simpler when you choose the instance/dynamic model, instead of the - static one. - Here is how you can create Table aliases in jOOQ: -

- -Table<TBookRecord> book = T_BOOK.as("b"); -Table<TAuthorRecord> author = T_AUTHOR.as("a"); - -// If you choose not to generate a static meta model, this becomes even better -TBook book = T_BOOK.as("b"); -TAuthor author = T_AUTHOR.as("a"); - -

Now, if you want to reference any fields from those Tables, you may - not use the original T_BOOK or T_AUTHOR meta-model objects anymore. - Instead, you have to get the fields from the new book and author Table - aliases:

- - bookID = book.getField(TBook.ID); -Field authorID = author.getField(TAuthor.ID); - -// Or with the instance field model: -Field bookID = book.ID; -Field authorID = author.ID;]]> - -

- So this is how the above SQL statement would read in jOOQ: -

-create.select(authorID, bookID) - .from(author) - .join(book).on(authorID.equal(book.getField(T_BOOK.AUTHOR_ID))); - -// Or with the instance field model: -create.select(author.ID, book.ID) - .from(author) - .join(book).on(author.ID.equal(book.AUTHOR_ID)) - - -

Aliasing nested selects as tables

-

There is an interesting, more advanced example of how you can select - from an aliased nested select in the manual's section about -

- - -

Aliasing fields

-

Fields can also be aliased independently from Tables. Most often, - this is done when using functions or aggregate operators. Here is an - example:

- SELECT FIRST_NAME || ' ' || LAST_NAME author, COUNT(*) books - FROM T_AUTHOR - JOIN T_BOOK ON T_AUTHOR.ID = AUTHOR_ID -GROUP BY FIRST_NAME, LAST_NAME; -

Here is how it's done with jOOQ:

-Record record = create.select( - concat(T_AUTHOR.FIRST_NAME, " ", T_AUTHOR.LAST_NAME).as("author"), - count().as("books")) - .from(T_AUTHOR) - .join(T_BOOK).on(T_AUTHOR.ID.equal(T_BOOK.AUTHOR_ID)) - .groupBy(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME).fetchAny(); -

When you alias Fields like above, you can access those Fields' values using the alias name:

-System.out.println("Author : " + record.getValue("author")); -System.out.println("Books : " + record.getValue("books")); -
-
- - -
- Nested SELECT using the IN operator - -

The IN operator for use in semi-joins or anti-joins

-

- In addition to a list of constant values, the IN operator in - - also supports a - as an argument. - This can be any type of select as - discussed in the manual's section about - . - However, you must - ensure yourself, that the provided Select will only select a single - Field. -

-

Let's say you want to select books by authors born in 1920. Of - course, this is possible with a plain JOIN as well, but let's say we - want to use the IN operator. Then you have two possibilities:

- - -SELECT * - FROM T_BOOK - WHERE T_BOOK.AUTHOR_ID IN ( - SELECT ID FROM T_AUTHOR - WHERE T_AUTHOR.BORN = 1920) - --- OR: - -SELECT T_BOOK.* - FROM T_BOOK - JOIN T_AUTHOR ON (T_BOOK.AUTHOR_ID = T_AUTHOR.ID - AND T_AUTHOR.BORN = 1920) -create.select() - .from(T_BOOK) - .where(T_BOOK.AUTHOR_ID.in( - create.select(T_AUTHOR.ID).from(T_AUTHOR) - .where(T_AUTHOR.BORN.equal(1920)))); - -// OR: - -create.select(T_BOOK.getFields()) - .from(T_BOOK) - .join(T_AUTHOR).on(T_BOOK.AUTHOR_ID.equal(TAuthor.ID) - .and(T_AUTHOR.BORN.equal(1920))); -
-
- - -
- Nested SELECT using the EXISTS operator - -

The EXISTS operator for use in semi-joins or anti-joins

-

The EXISTS operator is rather independent and can stand any place - where there may be a new condition:

-
    -
  • It may be placed right after a WHERE keyword
  • -
  • It may be the right-hand-side of a boolean operator
  • -
  • It may be placed right after a ON or HAVING keyword (although, this is less likely to be done...)
  • -
- -

This is reflected by the fact that an EXISTS clause is usually - created directly from the Factory:

- -Condition exists(Select<?> query); -Condition notExists(Select<?> query); - -

When you create such a Condition, it can then be connected to any - other condition using AND, OR operators (see also the manual's section - on - ). There are also quite a few - convenience methods, where they might be useful. For instance in the - itself:

- -Condition andExists(Select<?> select); -Condition andNotExists(Select<?> select); -Condition orExists(Select<?> select); -Condition orNotExists(Select<?> select); - -

Or in the :

- -SelectConditionStep whereExists(Select<?> select); -SelectConditionStep whereNotExists(Select<?> select); - -

Or in the :

- -SelectConditionStep andExists(Select<?> select); -SelectConditionStep andNotExists(Select<?> select); -SelectConditionStep orExists(Select<?> select); -SelectConditionStep orNotExists(Select<?> select); - -

An example of how to use it is quickly given. Get all authors that haven't written any books:

- -SELECT * - FROM T_AUTHOR - WHERE NOT EXISTS (SELECT 1 - FROM T_BOOK - WHERE T_BOOK.AUTHOR_ID = T_AUTHOR.ID) -create.select() - .from(T_AUTHOR) - .whereNotExists(create.selectOne() - .from(T_BOOK) - .where(T_BOOK.AUTHOR_ID.equal(T_AUTHOR.ID))); - -
-
- - -
- Other types of nested SELECT - -

Comparison with single-field SELECT clause

-

If you can ensure that a nested SELECT will only return one Record - with one Field, then you can test for equality. This is how it is done - in SQL:

- - -SELECT * - FROM T_BOOK - WHERE T_BOOK.AUTHOR_ID = ( - SELECT ID - FROM T_AUTHOR - WHERE LAST_NAME = 'Orwell') -create.select() - .from(T_BOOK) - .where(T_BOOK.AUTHOR_ID.equal(create - .select(T_AUTHOR.ID) - .from(T_AUTHOR) - .where(T_AUTHOR.LAST_NAME.equal("Orwell")))); - - -

More examples like the above can be guessed from the - API, as documented in the manual's section about - . For the = operator, the available comparisons are these:

- -Condition equal(Select<?> query); -Condition equalAny(Select<?> query); -Condition equalAll(Select<?> query); - - -

Selecting from a SELECT - SELECT acts as a Table

-

Often, you need to nest a SELECT statement simply because SQL is - limited in power. For instance, if you want to find out which author - has written the most books, then you cannot do this:

- - SELECT AUTHOR_ID, count(*) books - FROM T_BOOK -GROUP BY AUTHOR_ID -ORDER BY books DESC - -

Instead, you have to do this (or something similar). For jOOQ, this - is an excellent example, combining various SQL features into a single - statement. Here's how to do it:

- - -SELECT nested.* FROM ( - SELECT AUTHOR_ID, count(*) books - FROM T_BOOK - GROUP BY AUTHOR_ID -) nested -ORDER BY nested.books DESC - - - -Table<Record> nested = - create.select(T_BOOK.AUTHOR_ID, count().as("books")) - .from(T_BOOK) - .groupBy(T_BOOK.AUTHOR_ID).asTable("nested"); - -create.select(nested.getFields()) - .from(nested) - .orderBy(nested.getField("books")); - - -

You'll notice how some verbosity seems inevitable when you combine nested SELECT statements with aliasing.

- -

Selecting a SELECT - SELECT acts as a Field

-

Now SQL is even more powerful than that. You can also have SELECT - statements, wherever you can have Fields. It get's harder and harder - to find good examples, because there is always an easier way to - express the same thing. But why not just count the number of books the - really hard way? :-) But then again, maybe you want to take advantage - of Oracle Scalar Subquery Caching

- - - SELECT LAST_NAME, ( - SELECT COUNT(*) - FROM T_BOOK - WHERE T_BOOK.AUTHOR_ID = T_AUTHOR.ID) books - FROM T_AUTHOR -ORDER BY books DESC - - - - -// The type of books cannot be inferred from the Select<?> -Field<Object> books = - create.selectCount() - .from(T_BOOK) - .where(T_BOOK.AUTHOR_ID.equal(T_AUTHOR.ID)) - .asField("books"); -create.select(T_AUTHOR.ID, books) - .from(T_AUTHOR) - .orderBy(books, T_AUTHOR.ID)); - -
-
- - -
- UNION and other set operations - -

jOOQ's set operation API

-

The - API directly supports the UNION - syntax for all types of Select as discussed in the manual's section about - . - It consists of these methods:

- -public interface Select<R extends Record> { - Select<R> union(Select<R> select); - Select<R> unionAll(Select<R> select); - Select<R> except(Select<R> select); - Select<R> intersect(Select<R> select); -} - -

Hence, this is how you can write a simple UNION with jOOQ:

- -SELECT TITLE - FROM T_BOOK - WHERE PUBLISHED_IN > 1945 -UNION -SELECT TITLE - FROM T_BOOK - WHERE AUTHOR_ID = 1 -create.select(TBook.TITLE) - .from(T_BOOK) - .where(T_BOOK.PUBLISHED_IN.greaterThan(1945)) - .union( -create.select(T_BOOK.TITLE) - .from(T_BOOK) - .where(T_BOOK.AUTHOR_ID.equal(1))); - - -

Nested UNIONs

-

In some SQL dialects, you can arbitrarily nest UNIONs to several - levels. Be aware, though, that SQLite, Derby and MySQL have serious - syntax limitations. jOOQ tries to render correct UNION SQL statements, - but unfortunately, you can create situations that will cause syntax - errors in the aforementioned dialects.

- -

An example of advanced UNION usage is the following statement in jOOQ:

-// Create a UNION of several types of books -Select<?> union = - create.select(T_BOOK.TITLE, T_BOOK.AUTHOR_ID).from(T_BOOK).where(T_BOOK.PUBLISHED_IN.greaterThan(1945)).union( - create.select(T_BOOK.TITLE, T_BOOK.AUTHOR_ID).from(T_BOOK).where(T_BOOK.AUTHOR_ID.equal(1))); - -// Now, re-use the above UNION and order it by author -create.select(union.getField(T_BOOK.TITLE)) - .from(union) - .orderBy(union.getField(T_BOOK.AUTHOR_ID).descending()); - -

This example does not seem surprising, when you have read the - previous chapters about - . - But when you check - out the rendered SQL:

- --- alias_38173 is an example of a generated alias, --- generated by jOOQ for union queries -SELECT alias_38173.TITLE FROM ( - SELECT T_BOOK.TITLE, T_BOOK.AUTHOR_ID FROM T_BOOK WHERE T_BOOK.PUBLISHED_IN > 1945 - UNION - SELECT T_BOOK.TITLE, T_BOOK.AUTHOR_ID FROM T_BOOK WHERE T_BOOK.AUTHOR_ID = 1 -) alias_38173 -ORDER BY alias_38173.AUTHOR_ID DESC - -

You can see that jOOQ takes care of many syntax pitfalls, when - you're not used to the various dialects' unique requirements. The - above automatic aliasing was added in order to be compliant with - MySQL's requirements about aliasing nested selects.

- -

Several UNIONs

-

It is no problem either for you to create SQL statements with several unions. Just write:

-Select<?> part1; -Select<?> part2; -Select<?> part3; -Select<?> part4; - -// [...] - -part1.union(part2).union(part3).union(part4); - -

UNION and the ORDER BY clause

-

- Strictly speaking, in SQL, you cannot order a subselect that is part - of a UNION operation. You can only order the whole set. In set theory, - or relational algebra, it wouldn't make sense to order subselects - anyway, as a set operation cannot guarantee order correctness. Often, - you still want to do it, because you apply a LIMIT to every subselect. - Let's say, you want to find the employees with the highest salary in - every department in Postgres syntax: -

- -SELECT * FROM ( - SELECT * FROM emp WHERE dept = 'IT' - ORDER BY salary LIMIT 1 -) UNION ( - SELECT * FROM emp WHERE dept = 'Marketing' - ORDER BY salary LIMIT 1 -) UNION ( - SELECT * FROM emp WHERE dept = 'R&D' - ORDER BY salary LIMIT 1 -) -create.selectFrom(EMP).where(DEPT.equal("IT")) - .orderBy(SALARY).limit(1) - .union( -create.selectFrom(EMP).where(DEPT.equal("Marketing")) - .orderBy(SALARY).limit(1)) - .union( -create.selectFrom(EMP).where(DEPT.equal("R&D") - .orderBy(SALARY).limit(1))) - - - - - -

There is a subtle difference between the above two queries. - In SQL, every UNION subselect is in fact a - , wrapped in parentheses. - In this example, the notion of "nested SELECT" and "subselect" are slightly - different.

-
-
- - -
- Functions and aggregate operators - -

Supporting for vendor-specific functions

-

jOOQ allows you to access native functions from your RDBMS. jOOQ - follows two strategies:

-
    -
  • Implement all SQL-92, SQL:1999, SQL:2003, and SQL:2008 standard - functions, aggregate operators, and window functions. Standard - functions could be - these functions as listed by O'Reilly.
  • -
  • Take the most useful of vendor-specific functions and simulate - them for other RDBMS, where they may not be supported. An example for - this are - Oracle Analytic Functions
  • -
- -

Functions

-

These are just a few functions in the Factory, so you get the idea:

- - rpad(Field field, Field length); -Field rpad(Field field, int length); -Field rpad(Field field, Field length, Field c); -Field rpad(Field field, int length, char c); -Field lpad(Field field, Field length); -Field lpad(Field field, int length); -Field lpad(Field field, Field length, Field c); -Field lpad(Field field, int length, char c); -Field replace(Field field, Field search); -Field replace(Field field, String search); -Field replace(Field field, Field search, Field replace); -Field replace(Field field, String search, String replace); -Field position(Field field, String search); -Field position(Field field, Field search);]]> - -

Aggregate functions

-

Aggregate functions work just like functions, even if they have a - slightly different semantics. Here are some examples from - Factory:

- - count(Field field); -AggregateFunction max(Field field); -AggregateFunction min(Field field); -AggregateFunction sum(Field field); -AggregateFunction avg(Field field); - - -// DISTINCT keyword in aggregate functions -AggregateFunction countDistinct(Field field); -AggregateFunction maxDistinct(Field field); -AggregateFunction minDistinct(Field field); -AggregateFunction sumDistinct(Field field); -AggregateFunction avgDistinct(Field field); - -// String aggregate functions -AggregateFunction groupConcat(Field field); -AggregateFunction groupConcatDistinct(Field field); -OrderedAggregateFunction listAgg(Field field); -OrderedAggregateFunction listAgg(Field field, String separator); - -// Statistical functions -AggregateFunction median(Field field); -AggregateFunction stddevPop(Field field); -AggregateFunction stddevSamp(Field field); -AggregateFunction varPop(Field field); -AggregateFunction varSamp(Field field); -]]> - -

A typical example of how to use an aggregate operator is when - generating the next key on insertion of an ID. When you want to - achieve something like this

- - -SELECT MAX(ID) + 1 AS next_id - FROM T_AUTHOR -create.select(max(ID).add(1).as("next_id")) - .from(T_AUTHOR); - - -

See also the section about -

- -

Ordered aggregate functions

-

Oracle and some other databases support ordered - aggregate functions. This means you can provide - an ORDER BY clause to an aggregate function, which will - be taken into consideration when aggregating. The best example - for this is LISTAGG() (also known as GROUP_CONCAT in other dialects). - The following query groups by authors and concatenates - their books' titles

- -SELECT LISTAGG(TITLE, ', ') - WITHIN GROUP (ORDER BY TITLE) -FROM BOOK -GROUP BY AUTHOR_ID -create.select(listAgg(BOOK.TITLE, ", ") - .withinGroupOrderBy(BOOK.TITLE)) - .from(BOOK) - .groupBy(BOOK.AUTHOR_ID) - - - -

Window functions

-

Most major RDBMS support the concept of window functions. jOOQ knows - of implementations in DB2, Oracle, Postgres, SQL Server, and Sybase - SQL Anywhere, - and supports most of their specific syntaxes. Window functions can be - used for things like calculating a "running total". The following example - fetches transactions and the running total for every transaction going - back to the beginning of the transaction table (ordered by booked_at). - - They are accessible from the previously seen AggregateFunction type using - the over() method: -

- - -SELECT booked_at, amount, - SUM(amount) OVER (PARTITION BY 1 - ORDER BY booked_at - ROWS BETWEEN UNBOUNDED PRECEDING - AND CURRENT ROW) AS total - FROM transactions -create.select(t.BOOKED_AT, t.AMOUNT, - sum(t.AMOUNT).over().partitionByOne() - .orderBy(t.BOOKED_AT) - .rowsBetweenUnboundedPreceding() - .andCurrentRow().as("total") - .from(TRANSACTIONS.as("t")); - -
-
- - -
- Stored procedures and functions - -

Interaction with stored procedures

-

- The full power of your database's vendor-specific extensions can hardly - be obtained outside of the - database itself. Most modern RDBMS support - their own procedural language. With jOOQ, stored procedures are - integrated easily -

- -

The main way to interact with your RDBMS's stored procedures and - functions is by using the generated artefacts. See the manual's - section about - - for more details - about the source code generation for stored procedures and functions. -

- -

Stored functions

-

When it comes to DSL, stored functions can be very handy in SQL - statements as well. Every stored function (this also applies to - FUNCTIONS in Oracle PACKAGES) can generate a Field representing a call - to that function. Typically, if you have this type of function in your - database:

- -CREATE OR REPLACE FUNCTION f_author_exists (author_name VARCHAR2) -RETURN NUMBER; - -

Then convenience methods like these are generated:

-// Create a field representing a function with another field as parameter -public static Field<BigDecimal> fAuthorExists(Field<String> authorName) { // [...] - -// Create a field representing a function with a constant parameter -public static Field<BigDecimal> fAuthorExists(String authorName) { // [...] - -

Let's say, you have a T_PERSON table with persons' names in it, and - you want to know whether there exists an author with precisely that - name, you can reuse the above stored function in a SQL query:

- - -SELECT T_PERSON.NAME, F_AUTHOR_EXISTS(T_PERSON.NAME) - FROM T_PERSON - --- OR: - -SELECT T_PERSON.NAME - FROM T_PERSON - WHERE F_AUTHOR_EXISTS(T_PERSON.NAME) = 1 - create.select(T_PERSON.NAME, Functions.fAuthorExists(T_PERSON.NAME)) - .from(T_PERSON); - -// OR: Note, the static import of Functions.* -create.select(T_PERSON.NAME) - .from(T_PERSON) - .where(fAuthorExists(T_PERSON.NAME)); - - -

Stored procedures

-

The notion of a stored procedure is implemented in most RDBMS by the - fact, that the procedure has no RETURN VALUE (like void in Java), but - it may well have OUT parameters. Since there is not a standard way how - to embed stored procedures in SQL, they cannot be integrated in jOOQ's - DSL either.

-
-
- - -
- Arithmetic operations and concatenation - -

Mathematical operations

-

- Your database can do the math for you. Most arithmetic operations are - supported, but also string concatenation can be very efficient if done - already in the database. -

-

Arithmetic operations are implemented just like - , with - similar limitations as far as type restrictions are concerned. You can - use any of these operators:

- - + - * / % - -

In order to express a SQL query like this one:

- SELECT ((1 + 2) * (5 - 3) / 2) % 10 FROM DUAL -

You can write something like this in jOOQ:

- create.select(val(1).add(2).mul(val(5).sub(3)).div(2).mod(10)); - -

Datetime arithmetic

-

jOOQ also supports the Oracle-style syntax for adding days to a Field<? extends java.util.Date>

- - SELECT SYSDATE + 3 FROM DUAL; - create.select(currentTimestamp().add(3)); - - -

- For more advanced datetime arithmetic, use the Factory's timestampDiff() and dateDiff() functions, - as well as jOOQ's built-in SQL standard INTERVAL data type support: -

-
    -
  • INTERVAL YEAR TO MONTH:
  • -
  • INTERVAL DAY TO SECOND:
  • -
- -

String concatenation

-

This is not really an arithmetic expression, but it's still an - expression with operators: The string concatenation. jOOQ - provides you with the Field's concat() method:

- -SELECT 'A' || 'B' || 'C' FROM DUAL - --- Or in MySQL: -SELECT concat('A', 'B', 'C') -  -// For all RDBMS, including MySQL: -create.select(concat("A", "B", "C")); - - - -
-
- - -
- The CASE clause - -

The two flavours of CASE

-

The CASE clause is part of the standard SQL syntax. While some RDBMS - also offer an IF clause, or a DECODE function, you can always rely on - the two types of CASE syntax:

- - -CASE WHEN T_AUTHOR.FIRST_NAME = 'Paulo' THEN 'brazilian' - WHEN T_AUTHOR.FIRST_NAME = 'George' THEN 'english' - ELSE 'unknown' -END - --- OR: - -CASE T_AUTHOR.FIRST_NAME WHEN 'Paulo' THEN 'brazilian' - WHEN 'George' THEN 'english' - ELSE 'unknown' -END -create.decode() - .when(T_AUTHOR.FIRST_NAME.equal("Paulo"), "brazilian") - .when(T_AUTHOR.FIRST_NAME.equal("George"), "english") - .otherwise("unknown"); - -// OR: - -create.decode().value(T_AUTHOR.FIRST_NAME) - .when("Paulo", "brazilian") - .when("George", "english") - .otherwise("unknown"); - - -

- In jOOQ, both syntaxes are supported (although, Derby only knows the - first one, which is more general). Unfortunately, both case and else - are reserved words in Java. jOOQ chose to use decode() from the Oracle - DECODE function, and otherwise(), which means the same as else. Please - note that in the above examples, all values were always constants. You - can of course also use Field instead of the various constants. -

-

A CASE clause can be used anywhere where you can place a Field. For - instance, you can SELECT the above expression, if you're selecting - from T_AUTHOR:

-SELECT T_AUTHOR.FIRST_NAME, [... CASE EXPR ...] AS nationality - FROM T_AUTHOR - - -

CASE clauses in an ORDER BY clause

-

Sort indirection is often implemented with a CASE clause of a - SELECT's ORDER BY clause. In SQL, this reads:

- -SELECT * -FROM T_AUTHOR -ORDER BY CASE FIRST_NAME WHEN 'Paulo' THEN 1 - WHEN 'George' THEN 2 - ELSE null - END - -

This will order your authors such that all 'Paulo' come first, then - all 'George' and everyone else last (depending on your RDBMS' handling - of NULL values in sorting). This is a very common task, such that jOOQ - simplifies its use:

-create.select() - .from(T_AUTHOR) - .orderBy(T_AUTHOR.FIRST_NAME.sortAsc("Paulo", "George")) - .execute(); -
-
- - -
- Type casting - -

Enforcing a specific type when you need it

-

jOOQ's source code generator tries to find the most accurate type - mapping between your vendor-specific data types and a matching Java - type. For instance, most VARCHAR, CHAR, CLOB types will map to String. - Most BINARY, BYTEA, BLOB types will map to byte[]. NUMERIC types will - default to java.math.BigDecimal, but can also be any of - java.math.BigInteger, Long, Integer, Short, Byte, Double, Float.

-

Sometimes, this automatic mapping might not be what you needed, or - jOOQ cannot know the type of a field (because you created it from a - ). - In those cases you would write SQL type CASTs like - this:

--- Let's say, your Postgres column LAST_NAME was VARCHAR(30) --- Then you could do this: -SELECT CAST(T_AUTHOR.LAST_NAME AS TEXT) FROM DUAL -

in jOOQ, you can write something like that:

- create.select(TAuthor.LAST_NAME.cast(PostgresDataType.TEXT)); -

The same thing can be achieved by casting a Field directly to - String.class, as TEXT is the default data type in Postgres to map to - Java's String

- create.select(TAuthor.LAST_NAME.cast(String.class)); -

The complete CAST API in Field consists of these three methods:

-public interface Field<T> { - <Z> Field<Z> cast(Field<Z> field); - <Z> Field<Z> cast(DataType<Z> type); - <Z> Field<Z> cast(Class<? extends Z> type); -} - -// And additional convenience methods in the Factory: -public class Factory { - <T> Field<T> cast(Object object, Field<T> field); - <T> Field<T> cast(Object object, DataType<T> type); - <T> Field<T> cast(Object object, Class<? extends T> type); - <T> Field<T> castNull(Field<T> field); - <T> Field<T> castNull(DataType<T> type); - <T> Field<T> castNull(Class<? extends T> type); -} -
-
- - -
- When it's just easier: Plain SQL - -

Plain SQL in jOOQ

-

A DSL is a nice thing to have, it feels "fluent" and "natural", - especially if it models a well-known language, such as SQL. But a DSL - is always expressed in another language (Java in this case), which was - not made for exactly that DSL. If it were, then jOOQ would be - implemented on a compiler-level, similar to Linq in .NET. But it's - not, and so, the DSL is limited. We have seen many functionalities - where the DSL becomes verbose. This can be especially true for:

-
    -
  • -
  • -
  • -
  • -
-

You'll probably find other examples. If verbosity scares you off, - don't worry. The verbose use-cases for jOOQ are rather rare, and when - they come up, you do have an option. Just write SQL the way you're - used to!

-

jOOQ allows you to embed SQL as a String in these contexts:

-
    -
  • Plain SQL as a condition
  • -
  • Plain SQL as a field
  • -
  • Plain SQL as a function
  • -
  • Plain SQL as a table
  • -
  • Plain SQL as a query
  • -
- -

To construct artefacts wrapping plain SQL, you should use any of - these methods from the Factory class:

- - field(String sql); -Field field(String sql, Object... bindings); - -// A field with a known data type - Field field(String sql, Class type); - Field field(String sql, Class type, Object... bindings); - Field field(String sql, DataType type); - Field field(String sql, DataType type, Object... bindings); - -// A field with a known name (properly escaped) -Field fieldByName(String... fieldName); - Field fieldByName(Class type, String... fieldName); - Field fieldByName(DataType type, String... fieldName) - -// A function - Field function(String name, Class type, Field... arguments); - Field function(String name, DataType type, Field... arguments); - -// A table -Table table(String sql); -Table table(String sql, Object... bindings); - -// A query without results (update, insert, etc) -Query query(String sql); -Query query(String sql, Object... bindings); - -// A query with results -ResultQuery resultQuery(String sql); -ResultQuery resultQuery(String sql, Object... bindings); - -// A query with results. This is the same as resultQuery(...).fetch(); -Result fetch(String sql); -Result fetch(String sql, Object... bindings);]]> - -

Apart from the general factory methods, plain SQL is useful also in - various other contexts. For instance, when adding a .where("a = b") - clause to a query. Hence, there exist several convenience methods - where plain SQL can be inserted usefully. This is an example - displaying all various use-cases in one single query:

- LAST_NAME = create.field("a.LAST_NAME"); - -// You can alias your plain SQL fields -Field COUNT1 = create.field("count(*) x"); - -// If you know a reasonable Java type for your field, you -// can also provide jOOQ with that type -Field COUNT2 = create.field("count(*) y", Integer.class); - - // Use plain SQL as select fields -create.select(LAST_NAME, COUNT1, COUNT2) - - // Use plain SQL as aliased tables (be aware of syntax!) - .from("t_author a") - .join("t_book b") - - // Use plain SQL for conditions both in JOIN and WHERE clauses - .on("a.id = b.author_id") - - // Bind a variable in plain SQL - .where("b.title != ?", "Brida") - - // Use plain SQL again as fields in GROUP BY and ORDER BY clauses - .groupBy(LAST_NAME) - .orderBy(LAST_NAME);]]> - -

There are some important things to keep in mind when using plain - SQL:

-
    -
  • jOOQ doesn't know what you're doing. You're on your own again! -
  • -
  • You have to provide something that will be syntactically correct. - If it's not, then jOOQ won't know. Only your JDBC driver or your - RDBMS will detect the syntax error.
  • -
  • You have to provide consistency when you use variable binding. The - number of ? must match the number of variables
  • -
  • Your SQL is inserted into jOOQ queries without further checks. - Hence, jOOQ can't prevent SQL injection.
  • -
- - - - - - - -
- Advanced topics - -

Overview

-

This section covers some advanced topics and features that don't fit into any other section.

-
- - - -
+
Master data and enumeration tables - -

Enumeration tables

-

Only MySQL and Postgres databases support true ENUM types natively. - Some other RDBMS allow you to map the concept of an ENUM data type to - a CHECK constraint, but those constraints can contain arbitrary SQL. - With jOOQ, you - can "simulate" ENUM types by declaring a table as a "master data - table" in the configuration. At code-generation time, this table will - be treated specially, and a Java enum type is generated from its data. -

- -

Configure master data tables

-

As previously discussed in the - - section, you can configure master data tables as follows:

- - - - - - [a table name] - - - [a column name] - - - [a column name] - - - [ ... ... ] - - ]]> - -

The results of this will be a Java enum that looks similar to this:

- { - - /** - * English - */ - en(1, "en", "English"), - - /** - * Deutsch - */ - de(2, "de", "Deutsch"), - - /** - * Français - */ - fr(3, "fr", "Français"), - - /** - * null - */ - pt(4, "pt", null), - ; - - private final Integer id; - private final String cd; - private final String description; - - // [ ... constructor and getters for the above properties ] -}]]> - -

In the above example, you can see how the configured primary key is - mapped to the id member, the configured literal column is mapped to - the cd member and the configured description member is mapped to the - description member and output as Javadoc. In other words, T_LANGUAGE - is a table with 4 rows and at least three columns.

-

The general contract (with jOOQ 1.6.2+) is that there must be

-
    -
  • A single-column primary key column of character or integer type -
  • -
  • An optional unique literal column of character or integer type - (otherwise, the primary key is used as enum literal)
  • -
  • An optional description column of any type
  • -
- -

Using MasterDataTypes

-

The point of MasterDataTypes in jOOQ is that they behave exactly - like true ENUM types. When the above T_LANGUAGE table is referenced by - T_BOOK, instead of generating foreign key navigation methods and a - LANGUAGE_ID Field<Integer>, a Field<TLanguage> is - generated:

- - { - - // [...] - public static final TableField LANGUAGE_ID = - new TableFieldImpl( /* ... */ ); -}]]> - -

Which can then be used in the TBookRecord directly:

- { - - // [...] - public TLanguage getLanguageId() { // [...] - public void setLanguageId(TLanguage value) { // [...] -}]]> - -

When to use MasterDataTypes

-

You can use master data types when you're actually mapping master - data to a Java enum. When the underlying table changes frequently, - those updates will not be reflected by the statically generated code. - Also, be aware that it will be difficult to perform actual JOIN - operations on the underlying table with jOOQ, once the master data - type is generated.

-
+
- -
- Custom data types and type conversion - -

Your custom type and its associated Converter

-

- When using a custom type in jOOQ, you need to let jOOQ know about - its associated . - A converter essentially has two generic type parameters: -

-
    -
  • <U>: The user-defined Java type. This could be , for instance.
  • -
  • <T>: The database / SQL type. This could be , for instance.
  • -
-

- The above conversion implies that you may want to use a GregorianCalendar for - SQL timestamps, rather than the timestamp type itself. You could then write - a Converter like this: -

- - { - - // Provide jOOQ with Class objects of and . These are used by - // jOOQ to discover your converter based on your custom type - // -------------------------------------------------------------------- - @Override - public Class fromType() { - return Timestamp.class; - } - - @Override - public Class toType() { - return GregorianCalendar.class; - } - - // Implement the type conversion methods. Convert your user-defined type - // "from" the SQL type when reading "from" the database, or "to" the SQL - // type when writing "to" the database. - @Override - public GregorianCalendar from(Timestamp databaseObject) { - GregorianCalendar calendar = (GregorianCalendar) Calendar.getInstance(); - calendar.setTimeInMillis(databaseObject.getTime()); - return calendar; - } - - @Override - public Timestamp to(GregorianCalendar userObject) { - return new Timestamp(userObject.getTime().getTime()); - } -} -]]> - -

- Such a Converter can now be used in various places of the jOOQ - API, especially when reading data from the database: -

- - result = -create.select(T_AUTHOR.DATE_OF_BIRTH) - .from(T_AUTHOR) - .fetch(0, new CalendarConverter());]]> - -

Using Converters in generated code

-

- A more common use-case, however, is to let jOOQ know about custom - types at code generation time. Use the following configuration elements - to specify, that you'd like to use GregorianCalendar for all database - fields that start with DATE_OF_ -

- - - - - - - java.util.GregorianCalendar - - - com.example.CalendarConverter - - - - - - - - java.util.GregorianCalendar - - - .*\.DATE_OF_.* - - -]]> - -

- The above configuration will lead to T_AUTHOR.DATE_OF_BIRTH - being generated like this: -

- -public class TAuthor extends UpdatableTableImpl<TAuthorRecord> { - - // [...] - public final TableField<TAuthorRecord, GregorianCalendar> DATE_OF_BIRTH = // [...] - // [...] - -} - -

- This means that the bound of <T> will be GregorianCalendar, - wherever you reference DATE_OF_BIRTH. jOOQ will use your custom - converter when binding variables and when fetching data from - : -

- - result = -create.selectFrom(T_AUTHOR) - .where(T_AUTHOR.DATE_OF_BIRTH.greaterThan(new GregorianCalendar(1980, 0, 1))) - .fetch(T_AUTHOR.DATE_OF_BIRTH);]]> - -

- Read more about advanced code generation configuration in - . -

- -

Using Converters for enum types

-

- Java's Enum types can be very useful in SQL too. - Some databases support enumeration types natively (MySQL, Postgres). - In other cases, you can use the above custom type configuration - also to provide jOOQ with Converters for your custom Enum types. - Instead of implementing , - you may choose to extend - instead, which provides some enum-specific default behaviour. -

-
+
+ Custom data types and type conversions +
+
+ Schema mapping + +
+ +
-
- Mapping generated schemata and tables - -

Mapping your DEV schema to a productive environment

-

You may wish to design your database in a way that you have several - instances of your schema. This is useful when you want to cleanly - separate data belonging to several customers / organisation units / - branches / users and put each of those entities' data in a separate - database or schema.

-

In our T_AUTHOR example this would mean that you provide a book - reference database to several companies, such as My Book World and - Books R Us. In that case, you'll probably have a schema setup like - this:

-
    -
  • DEV: Your development schema. This will be the schema that you - base code generation upon, with jOOQ
  • -
  • MY_BOOK_WORLD: The schema instance for My Book World
  • -
  • BOOKS_R_US: The schema instance for Books R Us
  • -
+
+ SQL execution + - -

Mapping DEV to MY_BOOK_WORLD with jOOQ

-

When a user from My Book World logs in, you want them to access the - MY_BOOK_WORLD schema using classes generated from DEV. This can be - achieved with the - - class, that you can equip your Factory's settings - with. Take the following example:

- -Settings settings = new Settings() - .withRenderMapping(new RenderMapping() - .withSchemata( - new MappedSchema().withInput("DEV") - .withOutput("MY_BOOK_WORLD"))); - -// Add the settings to the factory -Factory create = new Factory(connection, SQLDialect.ORACLE, settings); - -// Run queries with the "mapped" factory -create.selectFrom(T_AUTHOR).fetch(); - -

The query executed with a Factory equipped with the above mapping - will in fact produce this SQL statement:

- SELECT * FROM MY_BOOK_WORLD.T_AUTHOR -

Even if T_AUTHOR was generated from DEV.

- -

Mapping several schemata

-

Your development database may not be restricted to hold only one DEV - schema. You may also have a LOG schema and a MASTER schema. Let's say - the MASTER schema is shared among all customers, but each customer has - their own LOG schema instance. Then you can enhance your RenderMapping - like this (e.g. using an XML configuration file):

- - - - - - DEV - MY_BOOK_WORLD - - - LOG - MY_BOOK_WORLD_LOG - - - -]]> - -

Note, you can load the above XML file like this:

- -Settings settings = JAXB.unmarshal(new File("jooq-runtime.xml"), Settings.class); - -

This will map generated classes from DEV to MY_BOOK_WORLD, from LOG - to MY_BOOK_WORLD_LOG, but leave the MASTER schema alone. Whenever you - want to change your mapping configuration, you will have to create a - new Factory

- - -

Using a default schema

-

Another option to switch schema names is to use a default schema for - the Factory's underlying Connection. Many RDBMS support a USE or SET - SCHEMA command, which you can call like this:

- -// Set the default schema -Schema MY_BOOK_WORLD = ... -create.use(MY_BOOK_WORLD); - -// Run queries with factory having a default schema -create.selectFrom(T_AUTHOR).fetch(); -

Queries generated from the above Factory will produce this kind of SQL statement:

- --- the schema name is omitted from all SQL constructs. -SELECT * FROM T_AUTHOR - -

If you wish not to render any schema name at all, use the - following Settings property for this:

- - -Settings settings = new Settings() - .withRenderSchema(false); - -// Add the settings to the factory -Factory create = new Factory(connection, SQLDialect.ORACLE, settings); - -// Run queries that omit rendering schema names -create.selectFrom(T_AUTHOR).fetch(); - -

Mapping of tables

-

Not only schemata can be mapped, but also tables. If you are not the - owner of the database your application connects to, you might need to - install your schema with some sort of prefix to every table. In our - examples, this might mean that you will have to map DEV.T_AUTHOR to - something MY_BOOK_WORLD.MY_APP__T_AUTHOR, where MY_APP__ is a prefix - applied to all of your tables. This can be achieved by creating the - following mapping:

- -Settings settings = new Settings() - .withRenderMapping(new RenderMapping() - .withSchemata( - new MappedSchema().withInput("DEV") - .withOutput("MY_BOOK_WORLD") - .withTables( - new MappedTable().withInput("T_AUTHOR") - .withOutput("MY_APP__T_AUTHOR")))); - -// Add the settings to the factory -Factory create = new Factory(connection, SQLDialect.ORACLE, settings); - -// Run queries with the "mapped" factory -create.selectFrom(T_AUTHOR).fetch(); - -

The query executed with a Factory equipped with the above mapping will in fact produce this SQL statement:

-SELECT * FROM MY_BOOK_WORLD.MY_APP__T_AUTHOR - -

- Table mapping and schema mapping can be applied independently, by specifying several MappedSchema entries - in the above configuration. jOOQ will process them in order of appearance and map at first match. Note that - you can always omit a MappedSchema's output value, in case of which, only the table mapping is applied. - If you omit a MappedSchema's input value, the table mapping is applied to all schemata! -

- -

Mapping at code generation time

-

- Note that you can also hard-wire schema mapping in generated artefacts - at code generation time, e.g. when you have 5 developers with their own - dedicated developer databases, and a common integration database. In the - code generation configuration, you would then write. -

- - - - LUKAS_DEV_SCHEMA - - - PROD - -]]> -

- See the manual's section about - - for more details -

- + +
+ Query vs. ResultQuery +
+
+ Fetching + -
- Execute listeners and the jOOQ Console - -

ExecuteListener

-

- The - let you specify a list of classes. - The ExecuteListener is essentially an event listener for - Query, Routine, or ResultSet render, prepare, bind, execute, fetch steps. It is a - base type for loggers, debuggers, profilers, data collectors. Advanced ExecuteListeners - can also provide custom implementations of Connection, PreparedStatement and ResultSet - to jOOQ in apropriate methods. For convenience, consider extending - - instead of implementing this interface. -

-

- Here is a sample implementation of an ExecuteListener, that is simply counting - the number of queries per type that are being executed using jOOQ: -

+ +
+ Record vs. TableRecord + +
- + Arrays and Maps + +
-public class StatisticsListener extends DefaultExecuteListener { - public static Map STATISTICS = new HashMap(); +
+ RecordHandler + +
- // Count "start" events for every type of query executed by jOOQ - @Override - public void start(ExecuteContext ctx) { - Integer count = STATISTICS.get(ctx.type()); +
+ POJOs + +
- if (count == null) { - count = 0; - } +
+ Lazy fetching + +
- STATISTICS.put(ctx.type(), count + 1); - } -}]]> +
+ Many fetching + +
-

- Now, configure jOOQ's runtime to load your listener -

+
+ ResultSet fetching + +
- - - com.example.StatisticsListener - -]]> - -

- And log results any time with a snippet like this: -

- - -

- This may result in the following log output: -

- -15:16:52,982 INFO - TEST STATISTICS -15:16:52,982 INFO - --------------- -15:16:52,983 INFO - READ : 919 executions -15:16:52,983 INFO - WRITE : 117 executions -15:16:52,983 INFO - DDL : 2 executions -15:16:52,983 INFO - BATCH : 4 executions -15:16:52,983 INFO - ROUTINE : 21 executions -15:16:52,983 INFO - OTHER : 30 executions -

- Please read the - ExecuteListener Javadoc - for more details -

- -

jOOQ Console

-

- The ExecuteListener API was driven by a feature request by Christopher Deckers, who has - had the courtesy to contribute the jOOQ Console, a sample application interfacing - with jOOQ's ExecuteListeners. The jOOQ Console logs all queries executed by jOOQ and - displays them nicely in a Swing application. With the jOOQ Console's logger, you can: -

-
    -
  • Activate the console's DebugListener anytime (in-process or if the remote server is active).
  • -
  • View simple and batch queries and their parameters.
  • -
  • Reformat queries along with syntax highlighting for better readability.
  • -
  • View stack trace of originator of the call.
  • -
  • Dump the stack to stdout when in an IDE, to directly navigate to relevant classes.
  • -
  • Track execution time, binding time, parsing time, rows read, fields read.
  • -
  • Show/hide queries depending on their type (SELECT, UPDATE, etc.).
  • -
  • Sort any column (timing columns, queries, types, etc.)
  • -
  • Easy copy paste of rows/columns to Spreadsheet editors.
  • -
- -

- A short overview of such a debugging session can be seen here: -

-
- jOOQ Console example -
-

- Please note that the jOOQ Console is still experimental. - Any feedback is very welcome on - the jooq-user group -

-

jOOQ Console operation modes

-

- The jOOQ Console can be run in two different modes: -

-
    -
  • In-process mode: running in the same process as the queries you're analysing
  • -
  • "headless" mode: running remotely
  • -
- -

- Both modes will require that you set the - - in the Factory's settings. When using XML settings: -

- - - - org.jooq.debug.DebugListener - -]]> - -

- Or when using programmatic settings: -

- - -

In-process mode

-

- The in-process mode is useful for Swing applications or other, - locally run Java programs accessing the database via jOOQ. - In order to launch the jOOQ Console "in-process", specify the - previously documented settings and launch the Console as follows: -

- - - -

- Only in the in-process mode, you can execute ad-hoc queries directly - from the console, if you provide it with proper DatabaseDescriptor. - These queries are executed from the Editor pane which features: -

-
    -
  • SQL editing within the console.
  • -
  • Incremental search on tables.
  • -
  • Simple code completion with tables/columns/SQL keywords.
  • -
  • Syntax highlighting and formatting capabilities.
  • -
  • Results shown in one or several tabs.
  • -
  • Easy analysis of Logger output by copy/pasting/running queries in the Editor.
  • -
-
- jOOQ Console example -
- -

"Headless" mode

-

- In J2EE or other server/client environments, you may not be able - to run the console in the same process as your application. You - can then run the jOOQ Console in "headless" mode. In addition to - the previously documented settings, you'll have to start a - debugger server in your application process, that the console can - connect to: -

- -// Create a new RemoteDebuggerServer in your application that listens to -// incoming connections on a given port -SERVER = new RemoteDebuggerServer(DEBUGGER_PORT); - -

- Now start your application along with the debugger server - and launch the console with this command: -

- -java -jar jooq-console-2.1.0.jar [host] [port] - -

- Depending on your distribution, you may have to manually add - rsyntaxtextarea-1.5.0.jar and jOOQ artefacts on your classpath. -

- +
+ Data type conversion + +
+
- -
- Adding Oracle hints to queries - -

How to embed Oracle hints in SELECT

-

If you are closely coupling your application to an Oracle (or CUBRID) database, - you might need to be able to pass hints of the form /*+HINT*/ with - your SQL statements to the Oracle database. For example:

-SELECT /*+ALL_ROWS*/ FIRST_NAME, LAST_NAME - FROM T_AUTHOR - -

This can be done in jOOQ using the .hint() clause in your SELECT statement:

-create.select(FIRST_NAME, LAST_NAME) - .hint("/*+ALL_ROWS*/") - .from(T_AUTHOR); - -

Note that you can pass any string in the .hint() clause. If you use - that clause, the passed string will always be put in between the - SELECT [DISTINCT] keywords and the actual projection list

-
+
+ Batch execution +
+
+ Formatting + -
- The Oracle CONNECT BY clause - -

CONNECT BY .. STARTS WITH

-

If you are closely coupling your application to an Oracle (or CUBRID) database, - you can take advantage of some Oracle-specific features, such as the - CONNECT BY clause, used for hierarchical queries. The formal syntax - definition is as follows:

+ +
+ Text + +
--- SELECT .. --- FROM .. --- WHERE .. - CONNECT BY [NOCYCLE] condition [AND condition, ...] [START WITH condition] --- GROUP BY .. -

This can be done in jOOQ using the .connectBy(Condition) clauses in your SELECT statement:

-// Some Oracle-specific features are only available -// from the OracleFactory -OracleFactory create = new OracleFactory(connection); +
+ CSV + +
-// Get a table with elements 1, 2, 3, 4, 5 -create.select(create.rownum()) - .connectBy(create.level().lessOrEqual(5)) - .fetch();
+
+ XML + +
-

Here's a more complex example where you can recursively fetch - directories in your database, and concatenate them to a path:

- + HTML + +
- List paths = - ora.select(ora.sysConnectByPath(DIRECTORY.NAME, "/").substring(2)) - .from(DIRECTORY) - .connectBy(ora.prior(DIRECTORY.ID).equal(DIRECTORY.PARENT_ID)) - .startWith(DIRECTORY.PARENT_ID.isNull()) - .orderBy(ora.literal(1)) - .fetch(0);]]> - -

The output might then look like this

-+------------------------------------------------+ -|substring | -+------------------------------------------------+ -|C: | -|C:/eclipse | -|C:/eclipse/configuration | -|C:/eclipse/dropins | -|C:/eclipse/eclipse.exe | -+------------------------------------------------+ -|...21 record(s) truncated... - - +
+ JSON + +
+
+
+ Importing + -
- The Oracle 11g PIVOT clause - -

PIVOT (aggregate FOR column IN (columns))

-

If you are closely coupling your application to an Oracle database, - you can take advantage of some Oracle-specific features, such as the - PIVOT clause, used for statistical analyses. The formal syntax - definition is as follows:

--- SELECT .. - FROM table PIVOT (aggregateFunction [, aggregateFunction] FOR column IN (expression [, expression])) --- WHERE .. + +
+ CSV + +
-

- The PIVOT clause is available from the - - type, as pivoting is done directly on a table. - Currently, only Oracle's PIVOT clause is supported. Support for SQL Server's - PIVOT clause will be added later. Also, jOOQ may simulate PIVOT for other - dialects in the future. -

-
-
- - -
- jOOQ's relational division syntax - -

Relational division

-

- There is one operation in relational algebra that is not given - a lot of attention, because it is rarely used in real-world - applications. It is the relational division, the opposite operation - of the cross product (or, relational multiplication). - The following is an approximate definition of a relational division: -

- -Assume the following cross join / cartesian product -C = A × B - -Then it can be said that -A = C ÷ B -B = C ÷ A - - -

- With jOOQ, you can simplify using relational divisions - by using the following syntax: -

- -C.divideBy(B).on(C.ID.equal(B.C_ID)).returning(C.TEXT) - -

The above roughly translates to

- -SELECT DISTINCT C.TEXT FROM C "c1" -WHERE NOT EXISTS ( - SELECT 1 FROM B - WHERE NOT EXISTS ( - SELECT 1 FROM C "c2" - WHERE "c2".TEXT = "c1".TEXT - AND "c2".ID = B.C_ID - ) -) - -

- Or in plain text: Find those TEXT values in C - whose ID's correspond to all ID's in B. Note - that from the above SQL statement, it is immediately - clear that proper indexing is of the essence. - Be sure to have indexes on all columns referenced - from the on(...) and returning(...) clauses. -

- -

- For more information about relational division - and some nice, real-life examples, see -

- - -
-
- - -
- Exporting to XML, CSV, JSON, HTML, Text - -

Exporting with jOOQ

-

If you are using jOOQ for scripting purposes or in a slim, unlayered - application server, you might be interested in using jOOQ's exporting - functionality (see also importing functionality). You can export any - Result<Record> into any of these formats:

- -

XML

-

Export your results as XML:

-// Fetch books and format them as XML -String xml = create.selectFrom(T_BOOK).fetch().formatXML(); - -

The above query will result in an XML document looking like the following one:

- - - - - - - - - - 1 - 1 - 1984 - - - 2 - 1 - Animal Farm - - -]]> - -

CSV

-

Export your results as CSV:

-// Fetch books and format them as CSV -String csv = create.selectFrom(T_BOOK).fetch().formatCSV(); - -

The above query will result in a CSV document looking like the following one:

-ID;AUTHOR_ID;TITLE -1;1;1984 -2;1;Animal Farm - - -

JSON

-

Export your results as JSON:

- -// Fetch books and format them as JSON -String json = create.selectFrom(T_BOOK).fetch().formatJSON(); -

The above query will result in a JSON document looking like the following one:

-{fields:["ID","AUTHOR_ID","TITLE"], - records:[[1,1,"1984"],[2,1,"Animal Farm"]]} - -

HTML

-

Export your results as HTML:

-// Fetch books and format them as HTML -String html = create.selectFrom(T_BOOK).fetch().formatHTML(); -

The above query will result in an HTML document looking like the following one:

- - - - ID - AUTHOR_ID - TITLE - - - - - 1 - 1 - 1984 - - - 2 - 1 - Animal Farm - - -]]> - -

Text

-

Export your results as text:

-// Fetch books and format them as text -String text = create.selectFrom(T_BOOK).fetch().format(); - -

The above query will result in a text document looking like the following one:

-+---+---------+-----------+ -| ID|AUTHOR_ID|TITLE | -+---+---------+-----------+ -| 1| 1|1984 | -| 2| 1|Animal Farm| -+---+---------+-----------+ -
+
+ XML + +
+
+
+ CRUD with UpdatableRecords + -
- Importing data from XML, CSV - -

Importing with jOOQ

-

If you are using jOOQ for scripting purposes or in a slim, unlayered - application server, you might be interested in using jOOQ's importing - functionality (see also exporting functionality). You can import data - directly into a table from any of these formats:

+ +
+ Simple CRUD + +
-

CSV

-

The below CSV data represents two author records that may have been - exported previously, by jOOQ's exporting functionality, and then - modified in Microsoft Excel or any other spreadsheet tool:

+
+ Non-updatable records + +
-ID;AUTHOR_ID;TITLE -1;1;1984 -2;1;Animal Farm +
+ Optimistic locking + +
-

With jOOQ, you can load this data using various parameters from the - loader API. A simple load may look like this:

- -Factory create = new Factory(connection, SQLDialect.ORACLE); - -// Load data into the T_AUTHOR table from an input stream -// holding the CSV data. -create.loadInto(T_AUTHOR) - .loadCSV(inputstream) - .fields(ID, AUTHOR_ID, TITLE) - .execute(); - -

Here are various other examples:

-// Ignore the AUTHOR_ID column from the CSV file when inserting -create.loadInto(T_AUTHOR) - .loadCSV(inputstream) - .fields(ID, null, TITLE) - .execute(); - -// Specify behaviour for duplicate records. -create.loadInto(T_AUTHOR) - - // choose any of these methods - .onDuplicateKeyUpdate() - .onDuplicateKeyIgnore() - .onDuplicateKeyError() // the default - - .loadCSV(inputstream) - .fields(ID, null, TITLE) - .execute(); - -// Specify behaviour when errors occur. -create.loadInto(T_AUTHOR) - - // choose any of these methods - .onErrorIgnore() - .onErrorAbort() // the default - - .loadCSV(inputstream) - .fields(ID, null, TITLE) - .execute(); - -// Specify transactional behaviour where this is possible -// (e.g. not in container-managed transactions) -create.loadInto(T_AUTHOR) - - // choose any of these methods - .commitEach() - .commitAfter(10) - .commitAll() - .commitNone() // the default - - .loadCSV(inputstream) - .fields(ID, null, TITLE) - .execute(); - -

Any of the above configuration methods can be combined to achieve - the type of load you need. Please refer to the API's Javadoc to learn - about more details. Errors that occur during the load are reported by - the execute method's result:

- - loader = /* .. */ .execute(); - -// The number of processed rows -int processed = loader.processed(); - -// The number of stored rows (INSERT or UPDATE) -int stored = loader.stored(); - -// The number of ignored rows (due to errors, or duplicate rule) -int ignored = loader.ignored(); - -// The errors that may have occurred during loading -List errors = loader.errors(); -LoaderError error = errors.get(0); - -// The exception that caused the error -DataAccessException exception = error.exception(); - -// The row that caused the error -int rowIndex = error.rowIndex(); -String[] row = error.row(); - -// The query that caused the error -Query query = error.query();]]> - -

XML

-

This will be implemented soon...

-
+
+ Batch execution + +
+
+
+ DAOs + +
-
- Using JDBC batch operations - -

JDBC batch operations

-

With JDBC, you can easily execute several statements at once using - the addBatch() method. Essentially, there are two modes in JDBC

+
+ ExecuteListeners + +
-
    -
  1. Execute several queries without bind values
  2. -
  3. Execute one query several times with bind values
  4. -
+
+ Logging + +
-

In code, this looks like the following snippet:

- + Performance considerations + +
+ +
-// 2. a single query -// ----------------- -PreparedStatement stmt = connection.prepareStatement("INSERT INTO autho VALUES (?, ?)"); -stmt.setInt(1, 1); -stmt.setString(2, "Erich Gamma"); -stmt.addBatch(); +
+ Tools + -stmt.setInt(1, 2); -stmt.setString(2, "Richard Helm"); -stmt.addBatch(); + +
+ jOOQ Console + -stmt.setInt(1, 3); -stmt.setString(2, "Ralph Johnson"); -stmt.addBatch(); + +
+ Logger + +
-stmt.setInt(1, 4); -stmt.setString(2, "John Vlissides"); -stmt.addBatch(); +
+ Debugger + +
-int[] result = stmt.executeBatch();]]> +
+ Editor + +
+
+
+
+
+
+ Reference + -

This will also be supported by jOOQ

-

jOOQ supports executing queries in batch - mode as follows:

- +
+ Data types + +
-// 2. a single query -// ----------------- -create.batch(create.insertInto(AUTHOR, ID, NAME).values("?", "?")) - .bind(1, "Erich Gamma") - .bind(2, "Richard Helm") - .bind(3, "Ralph Johnson") - .bind(4, "John Vlissides") - .execute();]]>
- +
+ Functions + +
+ +
+ Glossary +