This version of the manual is outdated. For the latest version, follow this link: http://www.jooq.org/doc/3.0/manual.

The jOOQ User Manual. Multiple Pages : jOOQ classes and their usage : The Query and its various subtypesprevious : next

# SELECT statements

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

Use the DSL API when:

Use the regular API when:

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:

# 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 TAuthor and TBook 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)

# 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 org.jooq.Select interface extends org.jooq.ResultQuery, 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 section on the ResultQuery 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 getGeneratedKeys() 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 org.jooq.UpdateQuery 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 org.jooq.DeleteQuery 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.


The jOOQ User Manual. Multiple Pages : jOOQ classes and their usage : The Query and its various subtypesprevious : next

The jOOQ Logo