diff --git a/jOOQ-website/src/main/java/Transform.java b/jOOQ-website/src/main/java/Transform.java index 789091eb7c..ec5754e13f 100644 --- a/jOOQ-website/src/main/java/Transform.java +++ b/jOOQ-website/src/main/java/Transform.java @@ -38,42 +38,42 @@ * This library is distributed with a LIMITED WARRANTY. See the jOOQ License * and Maintenance Agreement for more details: http://www.jooq.org/eula */ -import static org.joox.JOOX.$; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintStream; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.xml.transform.Result; -import javax.xml.transform.Source; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.sax.SAXResult; -import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; - -import org.apache.commons.lang3.StringUtils; -import org.apache.fop.apps.FOUserAgent; -import org.apache.fop.apps.Fop; -import org.apache.fop.apps.FopFactory; -import org.apache.fop.apps.MimeConstants; -import org.jooq.Constants; -import org.joox.Context; -import org.joox.Each; -import org.joox.Filter; -import org.joox.Match; +import static org.joox.JOOX.$; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import org.apache.commons.lang3.StringUtils; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.Fop; +import org.apache.fop.apps.FopFactory; +import org.apache.fop.apps.MimeConstants; +import org.jooq.Constants; +import org.joox.Context; +import org.joox.Each; +import org.joox.Filter; +import org.joox.Match; /** * XSL transformation utility for HTML pages diff --git a/jOOQ-website/src/main/resources/manual-2.5.xml b/jOOQ-website/src/main/resources/manual-2.5.xml index 19f2292ae0..b260421b8f 100644 --- a/jOOQ-website/src/main/resources/manual-2.5.xml +++ b/jOOQ-website/src/main/resources/manual-2.5.xml @@ -37,7 +37,7 @@
The jOOQ User Manual. Multiple Pages - +

# Overview

This manual is divided into six main sections:

@@ -88,12 +88,12 @@

-
+
Preface - +

jOOQ's reason of being - compared to JPA

Java and SQL have come a long way. SQL is an "ancient", yet established and well-understood technology. Java is a legacy too, although its platform JVM allows for many new and contemporary languages built on top of it. Yet, after all these years, libraries dealing with the interface between SQL and Java have come and gone, leaving JPA to be a standard that is accepted only with doubts, short of any surviving options. @@ -126,21 +126,21 @@

SQL was never meant to be abstracted. To be confined in the narrow boundaries of heavy mappers, hiding the beauty and simplicity of relational data. SQL was never meant to be object-oriented. SQL was never meant to be anything other than... SQL!

-
+
Getting started with jOOQ - +

These chapters contain a quick overview of how to get started with this manual and with jOOQ. While the subsequent chapters contain a lot of reference information, this chapter here just wraps up the essentials.

-
+
How to read this manual - +

This section helps you correctly interpret this manual in the context of jOOQ.

@@ -150,28 +150,21 @@ The following are code blocks:

- - - - - -]]> - - + +]]>

These are useful to provide examples in code. Often, with jOOQ, it is even more useful to compare SQL code with its corresponding Java/jOOQ code. When this is done, the blocks are aligned side-by-side, with SQL usually being on the left, and Java usually being on the right:

- + - - +

Code block contents

@@ -179,13 +172,11 @@ create.select()]]>

- - - +Factory create = new Factory(connection, SQLDialect.ORACLE);]]>

Settings

@@ -206,16 +197,16 @@ Factory create = new Factory(connection, SQLDialect.ORACLE);]]>

See the manual's section about to learn more about the sample database.

-
+
The sample database used in this manual - +

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 language ( +CREATE TABLE language ( id NUMBER(7) NOT NULL PRIMARY KEY, cd CHAR(2) NOT NULL, description VARCHAR2(50) @@ -253,16 +244,16 @@ CREATE TABLE book_to_book_store ( PRIMARY KEY(name, book_id), CONSTRAINT fk_b2bs_book_store FOREIGN KEY (name) REFERENCES book_store (name) ON DELETE CASCADE, CONSTRAINT fk_b2bs_book FOREIGN KEY (book_id) REFERENCES 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

-
+
Different use cases for jOOQ - +

jOOQ has originally been created as a library for complete abstraction of JDBC and all database interaction. Various best practices that are frequently encountered in pre-existing software products are applied to this library. This includes:

@@ -291,23 +282,23 @@ CREATE TABLE book_to_book_store (

The following sections explain about various use cases for using jOOQ in your application.

-
+
jOOQ as a SQL builder - +

This is the most simple of all use cases, allowing for construction of valid SQL for any database. In this use case, you will not use and probably not even . Instead, you'll use jOOQ to wrap strings, literals and other user-defined objects into an object-oriented, type-safe AST modelling your SQL statements. An example is given here:

- + .getSQL();]]>

The SQL string that you can generate as such can then be executed using JDBC directly, using Spring's JdbcTemplate, using Apache DbUtils and many other tools. @@ -319,23 +310,23 @@ String sql = create.select(fieldByName("BOOK","TITLE"), fieldByName("AUTHOR","FI

  • : This section contains a lot of information about creating SQL statements using the jOOQ API
  • : This section contains information useful in particular to those that want to supply , , etc. as plain SQL to jOOQ, rather than through generated artefacts
  • -
    +
    jOOQ as a SQL builder with code generation - +

    In addition to using jOOQ as a , you can also use jOOQ's code generation features in order to compile your SQL statements using a Java compiler against an actual database schema. This adds a lot of power and expressiveness to just simply constructing SQL using custom strings and literals, as you can be sure that all database artefacts actually exist in the database, and that their type is correct. An example is given here:

    - + .getSQL();]]>

    The SQL string that you can generate as such can then be executed using JDBC directly, using Spring's JdbcTemplate, using Apache DbUtils and many other tools. @@ -347,29 +338,29 @@ String sql = create.select(BOOK.TITLE, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)

  • : This section contains a lot of information about creating SQL statements using the jOOQ API
  • : This section contains the necessary information to run jOOQ's code generator against your developer database
  • -
    +
    jOOQ as a SQL executor - +

    Instead of any tool mentioned in the previous chapters, you can also use jOOQ directly to execute your jOOQ-generated SQL statements. This will add a lot of convenience on top of the previously discussed API for typesafe SQL construction, when you can re-use the information from generated classes to fetch records and custom data types. An example is given here:

    - result = create.select(BOOK.TITLE, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .from(BOOK) .join(AUTHOR) .on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)) .where(BOOK.PUBLISHED_IN.equal(1948)) - .fetch();]]> + .fetch();]]>

    jOOQ doesn't stop here, though! You can execute any SQL with jOOQ. In other words, you can use any other SQL building tool and run the SQL statements with jOOQ. An example is given here:

    - result = create.fetch(sql); // Or execute that SQL with JDBC, fetching the ResultSet with jOOQ: ResultSet rs = connection.createStatement().executeQuery(sql); -Result result = create.fetch(rs);]]> +Result result = create.fetch(rs);]]>

    If you wish to use jOOQ as a SQL executor with (or without) code generation, the following sections of the manual will be of interest to you: @@ -389,17 +380,17 @@ Result result = create.fetch(rs);]]>

  • : This section contains a lot of information about executing SQL statements using the jOOQ API
  • : This section contains some useful information about the various ways of fetching data with jOOQ
  • -
    +
    jOOQ for CRUD - +

    This is probably the most complete use-case for jOOQ: Use all of jOOQ's features. Apart from jOOQ's fluent API for query construction, jOOQ can also help you execute everyday CRUD operations. An example is given here:

    - +}]]>

    If you wish to use all of jOOQ's features, the following sections of the manual will be of interest to you (including all sub-sections): @@ -423,12 +414,12 @@ for (AuthorRecord author : create.fetch(AUTHOR)) {

  • : This section contains the necessary information to run jOOQ's code generator against your developer database
  • : This section contains a lot of information about executing SQL statements using the jOOQ API
  • -
    +
    jOOQ for PROs - +

    jOOQ isn't just a library that helps you and SQL against your . jOOQ ships with a lot of tools. Here are some of the most important tools shipped with jOOQ:

    @@ -442,32 +433,32 @@ for (AuthorRecord author : create.fetch(AUTHOR)) {

    If you're a power user of your favourite, feature-rich database, jOOQ will help you access all of your database's vendor-specific features, such as OLAP features, stored procedures, user-defined types, vendor-specific SQL, functions, etc. Examples are given throughout this manual.

    -
    +
    Tutorials - +

    Don't have time to read the full manual? Here are a couple of tutorials that will get you into the most essential parts of jOOQ as quick as possible.

    -
    +
    jOOQ in 7 easy steps - +

    This manual section is intended for new users, to help them get a running application with jOOQ, quickly.

    -
    +
    Step 1: Preparation - +

    If you haven't already downloaded it, download jOOQ:
    https://sourceforge.net/projects/jooq/files/Release/ @@ -476,12 +467,12 @@ for (AuthorRecord author : create.fetch(AUTHOR)) {

    Alternatively, you can create a Maven dependency:

    - + org.jooq jooq {jooq-version} -]]> +]]>

    For this example, we'll be using MySQL. If you haven't already downloaded MySQL Connector/J, download it here:
    @@ -491,17 +482,17 @@ for (AuthorRecord author : create.fetch(AUTHOR)) {

    If you don't have a MySQL instance up and running yet, get XAMPP now! XAMPP is a simple installation bundle for Apache, MySQL, PHP and Perl

    -
    +
    Step 2: Your database - +

    We're going to create a database called "guestbook" and a corresponding "posts" table. Connect to MySQL via your command line client and type the following:

    -CREATE DATABASE guestbook; +CREATE DATABASE guestbook; CREATE TABLE `posts` ( `id` bigint(20) NOT NULL, @@ -510,13 +501,12 @@ CREATE TABLE `posts` ( `title` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ); - -
    +
    Step 3: Code generation - +

    In this step, we're going to use jOOQ's command line tools to generate classes that map to the Posts table we just created. More detailed information about how to set up the jOOQ code generator can be found here:
    @@ -526,7 +516,7 @@ CREATE TABLE `posts` ( The easiest way to generate a schema is to copy the jOOQ jar files (there should be 3) and the MySQL Connector jar file to a temporary directory. Then, create a guestbook.xml that looks like this:

    - + @@ -567,7 +557,7 @@ CREATE TABLE `posts` ( C:/workspace/MySQLTest/src -]]> +]]>

    Replace the username with whatever user has the appropriate privileges to query the database meta data. You'll also want to look at the other values and replace as necessary. Here are the two interesting properties:

    @@ -582,15 +572,15 @@ CREATE TABLE `posts` ( Once you have the JAR files and guestbook.xml in your temp directory, type this (use colons instead of semi-colons on UNIX/Linux systems):

    -java -classpath jooq-{jooq-version}.jar;jooq-meta-{jooq-version}.jar;jooq-codegen-{jooq-version}.jar;mysql-connector-java-5.1.18-bin.jar;. +java -classpath jooq-{jooq-version}.jar;jooq-meta-{jooq-version}.jar;jooq-codegen-{jooq-version}.jar;mysql-connector-java-5.1.18-bin.jar;. org.jooq.util.GenerationTool /guestbook.xml - +

    Note the prefix slash before guestbook.xml. Even though it's in our working directory, we need to prepend a slash, as the configuration file is loaded from the classpath. Replace the filenames with your filenames. In this example, jOOQ {jooq-version} is being used. If everything has worked, you should see this in your console output:

    -Nov 1, 2011 7:25:06 PM org.jooq.impl.JooqLogger info +Nov 1, 2011 7:25:06 PM org.jooq.impl.JooqLogger info INFO: Initialising properties : /guestbook.xml Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info INFO: Database parameters @@ -650,19 +640,17 @@ Nov 1, 2011 7:25:08 PM org.jooq.impl.JooqLogger info INFO: Packages fetched : 0 (0 included, 0 excluded) Nov 1, 2011 7:25:08 PM org.jooq.impl.JooqLogger info INFO: GENERATION FINISHED! : Total: 791.688ms, +9.143ms - - -
    +
    Step 4: Connect to your database - +

    Let's just write a vanilla main class in the project containing the generated classes:

    - +}]]>

    This is pretty standard code for establishing a MySQL connection.

    -
    +
    Step 5: Querying - +

    Let's add a simple query:

    - result = create.select().from(POSTS).fetch();]]> + result = create.select().from(POSTS).fetch();]]>

    First get an instance of Factory so we can write a simple SELECT query. We pass an instance of the MySQL connection to Factory. Note that the factory doesn't close the connection. We'll have to do that ourselves. @@ -713,29 +701,29 @@ Result result = create.select().from(POSTS).fetch();]]>

    We then use jOOQ's DSL to return an instance of Result. We'll be using this result in the next step.

    -
    +
    Step 6: Iterating - +

    After the line where we retrieve the results, let's iterate over the results and print out the data:

    - +}]]>

    The full program should now look like this:

    - -
    +}]]>
    Step 7: Explore! - +

    jOOQ has grown to be a comprehensive SQL library. For more information, please consider the manual:
    http://www.jooq.org/manual/ @@ -814,37 +801,37 @@ public class Main { This tutorial is the courtesy of Ikai Lan. See the original source here:
    http://ikaisays.com/2011/11/01/getting-started-with-jooq-a-tutorial/

    -
    +
    Using jOOQ in modern IDEs - +

    Feel free to contribute a tutorial!

    -
    +
    Using jOOQ with Spring - +

    Feel free to contribute a tutorial!

    -
    +
    A simple web application with jOOQ - +

    Feel free to contribute a tutorial!

    -
    +
    Dependencies - +

    jOOQ has no dependencies on any third-party libraries. This rule has some exceptions:

    @@ -859,14 +846,14 @@ public class Main {

    In order to build jOOQ, please download the sources from https://github.com/jOOQ/jOOQ and use Maven to build it, preferably in Eclipse.

    -
    +
    SQL building - +

    SQL is a declarative language that is hard to integrate into procedural, object-oriented, functional or any other type of programming languages. jOOQ's philosophy is to give SQL the credit it deserves and integrate SQL itself as an "internal domain specific language" directly into Java.

    @@ -876,12 +863,12 @@ public class Main {

    This section explains all about the various syntax elements involved with jOOQ's SQL building capabilities. For a complete overview of all syntax elements, please refer to the manual's section about

    -
    +
    The Factory class - +

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

    @@ -902,13 +889,13 @@ public class Main {

    With jOOQ 2.0, static factory methods have been introduced in order to make client 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.*; + import static org.jooq.impl.Factory.*;

    Note, that when working with Eclipse, you could also add the Factory to your favourites. This will allow to access functions even more fluently:

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

    The Factory as a Configuration object

    @@ -923,20 +910,19 @@ Factory.concat(Factory.trim(FIRST_NAME), Factory.trim(LAST_NAME));

    As a Configuration object, a Factory can construct , for later . An example is given here:

    - select = create.selectOne(); // Using the internally referenced Factory, the select statement can now be executed: -Result result = select.fetch();]]> -
    +Result result = select.fetch();]]>
    SQL Dialect - +

    While jOOQ tries to represent the SQL standard as much as possible, many features are vendor-specific to a given database and to its "SQL dialect". jOOQ models this using the enum type.

    @@ -946,26 +932,26 @@ Result result = select.fetch();]]>

    Some parts of the jOOQ API are officially supported only by a given subset of the supported SQL dialects. For instance, the , which is supported by the Oracle and CUBRID databases, is annotated with a annotation, as such:

    -CONNECT BY clause to the query */ @Support({ CUBRID, ORACLE }) -SelectConnectByConditionStep connectBy(Condition condition);]]> +SelectConnectByConditionStep connectBy(Condition condition);]]>

    jOOQ API methods which are not annotated with the annotation, or which are annotated with the Support annotation, but without any SQL dialects can be safely used in all SQL dialects. An example for this is the factory method:

    -... fields);]]> +SelectSelectStep select(Field... fields);]]>

    jOOQ's SQL clause simulation capabilities

    The aforementioned Support annotation does not only designate, which databases natively support a feature. It also indicates that a feature is simulated by jOOQ for some databases lacking this feature. An example of this is the , a predicate syntax defined by SQL:1999 and implemented only by H2, HSQLDB, and Postgres:

    - +

    Nevertheless, the IS DISTINCT FROM predicate is supported in all dialects, as its semantics can be expressed with an equivalent . For more details, see the manual's section about the . @@ -985,12 +971,12 @@ SelectSelectStep select(Field... fields);]]>

    jOOQ has a historic affinity to Oracle's SQL extensions. If something is supported in Oracle SQL, it has a high probability of making it into the jOOQ API

    -
    +
    Connection vs. DataSource - +

    Interact with JDBC Connections

    While you can use jOOQ for only, you can also run queries against a JDBC . Internally, jOOQ creates or objects from such a Connection, in order to execute statements. The normal operation mode is to provide a with a JDBC Connection, whose lifecycle you will control yourself. This means that jOOQ will not actively close connections, rollback or commit transactions. @@ -999,12 +985,12 @@ SelectSelectStep select(Field... fields);]]>

    If you're in a J2EE or Spring context, however, you may wish to use a instead. Currently, Connections obtained from such a DataSource will be closed after query execution by jOOQ. The semantics of such a close operation should be the returning of the connection into a connection pool, not the actual closing of the underlying physical connection. Typically, this makes sense in an environment using distributed JTA transactions. An example of using DataSources with jOOQ can be seen in the tutorial section about .

    -
    +
    Custom 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:

    @@ -1018,9 +1004,9 @@ SelectSelectStep select(Field... fields);]]>

    For example, if you want to indicate to jOOQ, that it should inline all bind variables, and execute static instead of binding its variables to , you can do so by using the following Factory:

    - +Factory create = new Factory(connection, dialect, settings);]]>

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

    @@ -1042,12 +1028,12 @@ Factory create = new Factory(connection, dialect, settings);]]> Please refer to the jOOQ runtime configuration XSD for more details:
    http://www.jooq.org/xsd/jooq-runtime-2.5.0.xsd

    -
    +
    Runtime schema and table mapping - +

    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. @@ -1067,7 +1053,7 @@ Factory create = new Factory(connection, dialect, settings);]]> 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 with. Take the following example:

    -Settings settings = new Settings() +Settings settings = new Settings() .withRenderMapping(new RenderMapping() .withSchemata( new MappedSchema().withInput("DEV") @@ -1077,13 +1063,13 @@ Factory create = new Factory(connection, dialect, settings);]]> Factory create = new Factory(connection, SQLDialect.ORACLE, settings); // Run queries with the "mapped" factory -create.selectFrom(AUTHOR).fetch(); +create.selectFrom(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.AUTHOR +SELECT * FROM MY_BOOK_WORLD.AUTHOR

    Even if AUTHOR was generated from DEV.

    @@ -1093,7 +1079,7 @@ create.selectFrom(AUTHOR).fetch(); 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):

    - + @@ -1106,13 +1092,13 @@ create.selectFrom(AUTHOR).fetch(); -]]> +]]>

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

    -Settings settings = JAXB.unmarshal(new File("jooq-runtime.xml"), Settings.class); +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 @@ -1124,40 +1110,40 @@ create.selectFrom(AUTHOR).fetch(); 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 +// Set the default schema Schema MY_BOOK_WORLD = ... create.use(MY_BOOK_WORLD); // Run queries with factory having a default schema -create.selectFrom(AUTHOR).fetch(); +create.selectFrom(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 AUTHOR +-- the schema name is omitted from all SQL constructs. +SELECT * FROM AUTHOR

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

    -Settings settings = new Settings() +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(AUTHOR).fetch(); +create.selectFrom(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.AUTHOR to something MY_BOOK_WORLD.MY_APP__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() +Settings settings = new Settings() .withRenderMapping(new RenderMapping() .withSchemata( new MappedSchema().withInput("DEV") @@ -1170,13 +1156,13 @@ create.selectFrom(AUTHOR).fetch(); Factory create = new Factory(connection, SQLDialect.ORACLE, settings); // Run queries with the "mapped" factory -create.selectFrom(AUTHOR).fetch(); +create.selectFrom(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__AUTHOR +SELECT * FROM MY_BOOK_WORLD.MY_APP__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! @@ -1186,20 +1172,20 @@ create.selectFrom(AUTHOR).fetch();

    Note that the manual's section about explains how you can hard-wire your schema mappings at code generation time

    -
    +
    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 +// A general, dialect-unspecific factory Factory create = new Factory(connection, SQLDialect.MYSQL); // A MySQL-specific factory -MySQLFactory create = new MySQLFactory(connection); +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:

    @@ -1210,23 +1196,23 @@ MySQLFactory create = new MySQLFactory(connection);

    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. By default, such a schema-specific Factory will not render the schema name.

    -
    +
    SQL Statements - +

    jOOQ currently supports 6 types of SQL statements. All of these statements are constructed from a Factory instance with an optional . If supplied with a Connection or DataSource, they can be executed. Depending on the , executed queries can return results.

    -
    +
    jOOQ's DSL and non-DSL API - +

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

    @@ -1234,22 +1220,21 @@ MySQLFactory create = new MySQLFactory(connection); Here is an example to illustrate what that means:

    - 1920 AND a.first_name = 'Paulo' - ORDER BY b.title]]> - result = + ORDER BY b.title]]> result = create.select() .from(AUTHOR.as("a")) .join(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();]]> + .fetch();]]>

    We'll see how the aliasing works later in the section about @@ -1259,16 +1244,16 @@ create.select()

    Many other frameworks have similar APIs with similar feature sets. Yet, what makes jOOQ special is its informal modelling a unified SQL dialect suitable for many vendor-specific dialects, and implementing that BNF notation as a hierarchy of interfaces in Java. This concept is extremely powerful, when with syntax completion. Not only can you code much faster, your SQL code will be compile-checked to a certain extent. An example of a DSL query equivalent to the previous one is given here:

    - result = create.select() .from(AUTHOR) .join(BOOK).on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)) - .fetch();]]> + .fetch();]]>

    Unlike other, simpler frameworks that use "fluent APIs" or "method chaining", jOOQ's BNF-based interface hierarchy will not allow bad query syntax. The following will not compile, for instance:

    - result = create.select() .join(BOOK).on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)) // ^^^^ "join" is not possible here @@ -1284,13 +1269,13 @@ Result result = create.select() Result result = create.select(rowNumber()) // ^^^^^^^^^ "over()" is missing here .from(AUTHOR) - .fetch();]]> + .fetch();]]>

    History of SQL building and incremental query building (a.k.a. the non-DSL API)

    Historically, jOOQ started out as an object-oriented SQL builder library like any other. This meant that all queries and their syntactic components were modeled as so-called , which delegate and to child components. This part of the API will be referred to as the non-DSL API, which is still maintained and used internally by jOOQ for incremental query building. An example of incremental query building is given here:

    - result = query.fetch();]]> +Result result = query.fetch();]]>

    This query is equivalent to the one shown before using the DSL syntax. In fact, internally, the DSL API constructs precisely this QueryObject. Note, that you can always access the SelectQuery object to switch between DSL and non-DSL APIs:

    - +query.addJoin(BOOK, BOOK.AUTHOR_ID.equal(AUTHOR.ID));]]>

    Mutability

    Note, that for historic reasons, the DSL API mixes mutable and immutable behaviour with respect to the internal representation of the being constructed. While creating , (such as functions) assumes immutable behaviour, creating does not. In other words, the following can be said:

    - +s2 == s3; // The internal object is always the same]]>

    Mutability may be removed in a future version of jOOQ.

    -
    +
    The SELECT statement - +

    When you don't just perform (i.e. SELECT * FROM your_table WHERE ID = ?), you're usually generating new record 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:

    - + - - +

    Details about the various clauses of this query will be provided in subsequent sections @@ -1396,14 +1380,14 @@ create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, count()) A very similar, but limited API is available, if you want to select from single physical tables in order to retrieve . 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:

    - SimpleSelectWhereStep selectFrom(Table table);]]> + SimpleSelectWhereStep selectFrom(Table 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:

    - + .fetchAny();]]>

    The simple SELECT API is limited in the way that it does not support any of these clauses: @@ -1417,41 +1401,39 @@ create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, count())

    In most parts of this manual, it is assumed that you do not use the simple SELECT API. For more information about the simple SELECT API, see the manual's section about .

    -
    +
    The SELECT clause - +

    The SELECT clause lets you project your own record types, referencing table fields, functions, arithmetic expressions, etc. The Factory provides several methods for expressing a SELECT clause:

    - + - s1 = create.select(BOOK.ID, BOOK.TITLE); Select s2 = create.select(BOOK.ID, trim(BOOK.TITLE));]]> - +

    Some commonly used projections can be easily created using convenience methods:

    - + - select1 = create.selectCount(); Select select2 = create.selectZero(); Select select2 = create.selectOne();]]> - +

    See more details about functions and expressions in the manual's section about @@ -1462,28 +1444,26 @@ Select select2 = create.selectOne();]]> The DISTINCT keyword can be included in the method name, constructing a SELECT clause

    - - - select1 = create.selectDistinct(BOOK.TITLE);]]> - -
    + + select1 = create.selectDistinct(BOOK.TITLE);]]> + +
    The FROM clause - +

    The SQL FROM clause allows for specifying any number of to select data from. The following are examples of how to form normal FROM clauses:

    - + - - +

    Read more about aliasing in the manual's section about . @@ -1494,12 +1474,11 @@ create.selectOne().from(BOOK.as("b"), AUTHOR.as("a"));]]> Apart from simple tables, you can pass any arbitrary to the jOOQ FROM clause. This may include in Oracle:

    - + - - +

    Note, in order to access the DbmsXplan package, you can use the to generate Oracle's SYS schema. @@ -1511,22 +1490,21 @@ FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(null, null, 'ALLSTATS'));]]> In many SQL dialects, FROM is a mandatory clause, in some it isn't. jOOQ allows you to omit the FROM clause, returning just one record. An example:

    - + - - +

    Read more about dual or dummy tables in the manual's section about . The following are examples of how to form normal FROM clauses:

    -
    +
    The JOIN clause - +

    jOOQ supports many different types of standard SQL JOIN operations:

    @@ -1545,7 +1523,7 @@ new Factory(SQLDialect.POSTGRES).selectOne().getSQL();]]> All of these JOIN methods can be called on types, or directly after the FROM clause for convenience. The following example joins AUTHOR and BOOK

    - result = create.select() @@ -1558,27 +1536,26 @@ Result result = create.select() .from(AUTHOR) .join(BOOK) .on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)) - .fetch();]]> + .fetch();]]>

    The two syntaxes will produce the same SQL statement. However, calling "join" on objects allows for more powerful, nested JOIN expressions (if you can handle the parentheses):

    - + - + .on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)));]]>
    • See the section about to learn more about the many ways to create objects in jOOQ.
    • @@ -1590,13 +1567,12 @@ create.select() Surprisingly, SQL does not allow to formally JOIN on well-known foreign key relationship information. Naturally, when you join BOOK to AUTHOR, you will want to do that based on the BOOK.AUTHOR_ID foreign key to AUTHOR.ID primary key relation. Not being able to do this in SQL leads to a lot of repetitive code, re-writing the same JOIN predicate again and again - especially, when your foreign keys contain more than one column. With jOOQ, when you use , you can use foreign key constraint information in JOIN expressions as such:

      - + - + .join(BOOK).onKey();]]>

      In case of ambiguity, you can also supply field references for your foreign keys, or the generated foreign key reference to the onKey() method. @@ -1607,136 +1583,129 @@ JOIN BOOK ON BOOK.AUTHOR_ID = AUTHOR.ID]]> Most often, you will provide jOOQ with JOIN conditions in the JOIN .. ON clause. SQL supports a different means of specifying how two tables are to be joined. This is the JOIN .. USING clause. Instead of a condition, you supply a set of fields whose names are common to both tables to the left and right of a JOIN operation. This can be useful when your database schema has a high degree of relational normalisation. An example:

      - + - + .join(BOOK).using(AUTHOR.AUTHOR_ID);]]>

      In schemas with high degrees of normalisation, you may also choose to use NATURAL JOIN, which takes no JOIN arguments as it joins using all fields that are common to the table expressions to the left and to the right of the JOIN operator. An example:

      - + - + .naturalJoin(BOOK);]]>

      Oracle's partitioned OUTER JOIN

      Oracle SQL ships with a special syntax available for OUTER JOIN clauses. According to the Oracle documentation about partitioned outer joins this can be used to fill gaps for simplified analytical calculations. jOOQ only supports putting the PARTITION BY clause to the right of the OUTER JOIN clause. The following example will create at least one record per AUTHOR and per existing value in BOOK.PUBLISHED_IN, regardless if an AUTHOR has actually published a book in that year.

      - + - + .on(BOOK.AUTHOR_ID.equal(AUTHOR.ID));]]> - +
    The WHERE clause - +

    The WHERE clause can be used for JOIN or filter predicates, in order to restrict the data returned by the supplied to the previously specified and . Here is an example:

    - + - + .and(BOOK.TITLE.equal("1984"));]]>

    The above syntax is convenience provided by jOOQ, allowing you to connect the supplied in the WHERE clause with another condition using an AND operator. You can of course also create a more complex condition and supply that to the WHERE clause directly (observe the different placing of parentheses). The results will be the same:

    - + - + BOOK.TITLE.equal("1984")));]]>

    You will find more information about creating later in the manual.

    -
    +
    The CONNECT BY clause - +

    The Oracle database knows a very succinct syntax for creating hierarchical queries: the CONNECT BY clause, which is fully supported by jOOQ, including all related functions and pseudo-columns. A more or less formal definition of this clause is given here:

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

    An example for an iterative query, iterating through values between 1 and 5 is this:

    - + - + .connectBy(level().lessOrEqual(5));]]>

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

    - + - - +

    The output might then look like this

    -+------------------------------------------------+ ++------------------------------------------------+ |substring | +------------------------------------------------+ |C: | @@ -1746,7 +1715,7 @@ ORDER BY 1]]> |C:/eclipse/eclipse.exe | +------------------------------------------------+ |...21 record(s) truncated... - +

    Some of the supported functions and pseudo-columns are these (available from the ): @@ -1764,23 +1733,22 @@ ORDER BY 1]]>

    Note that this syntax is also supported in the CUBRID database.

    -
    +
    The GROUP BY clause - +

    GROUP BY can be used to create unique groups of data, to form aggregations, to remove duplicates and for other reasons. It will transform your previously defined , and return only one record per unique group as specified in this clause. For instance, you can group books by BOOK.AUTHOR_ID:

    - + - + .groupBy(AUTHOR_ID);]]>

    As defined in the SQL standard, when grouping, you may no longer project any columns that are not a formal part of the GROUP BY clause, or . The above example counts all books per author @@ -1791,13 +1759,12 @@ GROUP BY AUTHOR_ID]]> MySQL has a peculiar way of not adhering to this standard behaviour. This is documented in the MySQL manual. In short, with MySQL, you can also project any other field that are not part of the GROUP BY clause. The projected values will just be arbitrary values from within the group. You cannot rely on any ordering. For example:

    - + - + .groupBy(AUTHOR_ID);]]>

    This will return an arbitrary title per author. jOOQ supports this syntax, as jOOQ is not doing any checks internally, about the consistence of tables/fields/functions that you provide it. @@ -1808,68 +1775,64 @@ GROUP BY AUTHOR_ID]]> jOOQ supports empty GROUP BY () clauses as well. This will result in that return only one record.

    - + - + .groupBy();]]>

    ROLLUP(), CUBE() and GROUPING SETS()

    Some databases support the SQL standard grouping functions and some extensions thereof. See the manual's section about for more details.

    -
    +
    The HAVING clause - +

    The HAVING clause is commonly used to further restrict data resulting from a previously issued . An example, selecting only those authors that have written at least two books:

    - + = 2]]> -= 2]]> + .having(count().greaterOrEqual(2));]]>

    According to the SQL standard, you may omit the GROUP BY clause and still issue a HAVING clause. This will implicitly GROUP BY (). jOOQ also supports this syntax. The following example selects one record, only if there are at least 4 books in the books table:

    - + = 4]]> -= 4]]> + .having(count().greaterOrEqual(4));]]> -
    +
    The ORDER BY clause - +

    Databases are allowed to return data in any arbitrary order, unless you explicitly declare that order in the ORDER BY clause. In jOOQ, this is straight-forward:

    - + - + .orderBy(BOOK.AUTHOR_ID.asc(), BOOK.TITLE.desc());]]>

    Any jOOQ can be transformed into an by calling the asc() and desc() methods. @@ -1880,13 +1843,12 @@ ORDER BY AUTHOR_ID ASC, TITLE DESC]]> The SQL standard allows for specifying integer literals (, not !) to reference column indexes from the projection (). This may be useful if you do not want to repeat a lengthy expression, by which you want to order - although most databases also allow for referencing in the ORDER BY clause. An example of this is given here:

    - + - + .orderBy(one().asc(), inline(2).desc());]]>

    Note, how one() is used as a convenience short-cut for inline(1) @@ -1897,109 +1859,106 @@ ORDER BY 1 ASC, 2 DESC]]> A few databases support the SQL standard "null ordering" clause in sort specification lists, to define whether NULL values should come first or last in an ordered result.

    - + - + BOOK.CO_AUTHOR_ID.asc().nullsLast());]]>

    If your database doesn't support this syntax, jOOQ simulates it using a as follows

    - + - + BOOK.CO_AUTHOR_ID.asc().nullsLast());]]>

    Ordering using CASE expressions

    Using in SQL ORDER BY clauses is a common pattern, if you want to introduce some sort indirection / sort mapping into your queries. As with SQL, you can add any type of into your ORDER BY clause. For instance, if you have two favourite books that you always want to appear on top, you could write:

    - + - + .otherwise(2).asc());]]>

    But writing these things can become quite verbose. jOOQ supports a convenient syntax for specifying sort mappings. The same query can be written in jOOQ as such:

    - + .orderBy(BOOK.TITLE.sortAsc("1984", "Animal Farm"));]]>

    More complex sort indirections can be provided using a Map:

    -() {{ put("1984", 1); put("Animal Farm", 13); put("The jOOQ book", 10); - }}));]]> + }}));]]>

    Of course, you can combine this feature with the previously discussed NULLS FIRST / NULLS LAST feature. So, if in fact these two books are the ones you like least, you can put all NULLS FIRST (all the other books):

    - + .orderBy(BOOK.TITLE.sortAsc("1984", "Animal Farm").nullsFirst());]]>

    jOOQ's understanding of SELECT .. ORDER BY

    The SQL standard defines that a "query expression" can be ordered, and that query expressions can contain , whose subqueries cannot be ordered. While this is defined as such in the SQL standard, many databases allowing for the non-standard in one way or another, do not adhere to this part of the SQL standard. Hence, jOOQ allows for ordering all SELECT statements, regardless whether they are constructed as a part of a UNION or not. Corner-cases are handled internally by jOOQ, by introducing synthetic subselects to adhere to the correct syntax, where this is needed.

    -
    +
    The LIMIT .. OFFSET clause - +

    While being extremely useful for every application that does paging, or just to limit result sets to reasonable sizes, this clause is not yet part of any SQL standard (up until SQL:2008). Hence, there exist a variety of possible implementations in various SQL dialects, concerning this limit clause. jOOQ chose to implement the LIMIT .. OFFSET clause as understood and supported by MySQL, H2, HSQLDB, Postgres, and SQLite. Here is an example of how to apply limits with jOOQ:

    - +

    This will limit the result to 1 books starting with the 2nd book (starting at offset 0!). limit() is supported in all dialects, offset() in all but Sybase ASE, which has no reasonable means to simulate it. This is how jOOQ simulates the above query in various SQL dialects:

    - 1 AND ROWNUM_98843777 <= 3 -]]> +]]>

    As you can see, jOOQ will take care of the incredibly painful ROW_NUMBER() OVER() (or ROWNUM for Oracle) filtering in subselects for you, you'll just have to write limit(1).offset(2) in any dialect. @@ -2044,39 +2003,37 @@ AND ROWNUM_98843777 <= 3

    As can be seen in the above example, writing correct SQL can be quite tricky, depending on the SQL dialect. For instance, with SQL Server, you cannot have an ORDER BY clause in a subquery, unless you also have a TOP clause. This is illustrated by the fact that jOOQ renders a TOP 100 PERCENT clause for you. The same applies to the fact that ROW_NUMBER() OVER() needs an ORDER BY windowing clause, even if you don't provide one to the jOOQ query. By default, jOOQ adds ordering by the first column of your projection.

    -
    +
    The FOR UPDATE clause - +

    For inter-process synchronisation and other reasons, you may choose to use the SELECT .. FOR UPDATE clause to indicate to the database, that a set of cells or records should be locked by a given transaction for subsequent updates. With jOOQ, this can be achieved as such:

    - + - + .forUpdate();]]>

    The above example will produce a record-lock, locking the whole record for updates. Some databases also support cell-locks using FOR UPDATE OF ..

    - + - + .forUpdate().of(BOOK.TITLE);]]>

    Oracle goes a bit further and also allows to specify the actual locking behaviour. It features these additional clauses, which are all supported by jOOQ: @@ -2090,15 +2047,15 @@ FOR UPDATE OF TITLE]]> With jOOQ, you can use those Oracle extensions as such:

    - +create.select().from(BOOK).where(BOOK.ID.equal(3)).forUpdate().skipLocked();]]>

    FOR UPDATE in CUBRID and SQL Server

    The SQL standard specifies a FOR UPDATE clause to be applicable for cursors. Most databases interpret this as being applicable for all SELECT statements. An exception to this rule are the CUBRID and SQL Server databases, that do not allow for any FOR UPDATE clause in a regular SQL SELECT statement. jOOQ simulates the FOR UPDATE behaviour, by locking record by record with JDBC. JDBC allows for specifying the flags TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE for any statement, and then using ResultSet.updateXXX() methods to produce a cell-lock / row-lock. Here's a simplified example in JDBC:

    - +}]]>

    The main drawback of this approach is the fact that the database has to maintain a scrollable cursor, whose records are locked one by one. This can cause a major risk of deadlocks or race conditions if the JDBC driver can recover from the unsuccessful locking, if two Java threads execute the following statements:

    - +SELECT * FROM author ORDER BY id DESC;]]>

    So use this technique with care, possibly only ever locking single rows! @@ -2135,12 +2092,12 @@ SELECT * FROM author ORDER BY id DESC;]]>

    Note, that jOOQ also supports optimistic locking, if you're doing simple CRUD. This is documented in the section's manual about .

    -
    +
    UNION, INTERSECTION and EXCEPT - +

    SQL allows to perform set operations as understood in standard set theory on result sets. These operations include unions, intersections, subtractions. For two subselects to be combinable by such a set operator, each subselect must return a of the same arity and type.

    @@ -2150,13 +2107,12 @@ SELECT * FROM author ORDER BY id DESC;]]> These operators combine two results into one. While UNION removes all duplicate records resulting from this combination, UNION ALL leaves subselect results as they are. Typically, you should prefer UNION ALL over UNION, if you don't really need to remove duplicates. The following example shows how to use such a UNION operation in jOOQ.

    - + - +create.selectFrom(BOOK).where(BOOK.ID.equal(5)));]]>

    INTERSECT [ ALL ] and EXCEPT [ ALL ]

    @@ -2168,76 +2124,73 @@ create.selectFrom(BOOK).where(BOOK.ID.equal(5)));]]> As previously mentioned in the manual's section about the , jOOQ has slightly changed the semantics of these set operators. While in SQL, a subselect may not contain any or (unless you wrap the subselect into a ), jOOQ allows you to do so. In order to select both the youngest and the oldest author from the database, you can issue the following statement with jOOQ (rendered to the MySQL dialect):

    - + - + .orderBy(AUTHOR.DATE_OF_BIRTH.desc()).limit(1));]]> -
    +
    Oracle-style hints - +

    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 AUTHOR +SELECT /*+ALL_ROWS*/ FIRST_NAME, LAST_NAME + FROM AUTHOR

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

    -create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) +create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .hint("/*+ALL_ROWS*/") - .from(AUTHOR); + .from(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

    -
    +
    The INSERT statement - +

    The INSERT statement is used to insert new records into a database table. Records can either be supplied using a VALUES() constructor, or a SELECT statement. jOOQ supports both types of INSERT statements. An example of an INSERT statement using a VALUES() constructor is given here:

    - + INSERT INTO AUTHOR (ID, FIRST_NAME, LAST_NAME) -VALUES (100, 'Hermann', 'Hesse'); -create.insertInto(AUTHOR, +VALUES (100, 'Hermann', 'Hesse');create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) - .values(100, "Hermann", "Hesse"); + .values(100, "Hermann", "Hesse");

    INSERT multiple rows with the VALUES() constructor

    The SQL standard specifies that multiple rows can be supplied to the VALUES() constructor in an INSERT statement. Here's an example of a multi-record INSERT

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

    jOOQ tries to stay close to actual SQL. In detail, however, Java's expressiveness is limited. That's why the values() clause is repeated for every record in multi-record inserts. @@ -2246,30 +2199,29 @@ VALUES (100, 'Hermann', 'Hesse'), Some RDBMS do not support inserting several records in a single statement. In those cases, jOOQ simulates multi-record INSERTs using the following SQL:

    - + INSERT INTO AUTHOR (ID, FIRST_NAME, LAST_NAME) SELECT 100, 'Hermann', 'Hesse' FROM DUAL UNION ALL -SELECT 101, 'Alfred', 'Döblin' FROM DUAL; -create.insertInto(AUTHOR, +SELECT 101, 'Alfred', 'Döblin' FROM DUAL;create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .values(100, "Hermann", "Hesse") .values(101, "Alfred", "Döblin"); - +

    INSERT using jOOQ's alternative syntax

    MySQL (and some other RDBMS) allow for using a non-SQL-standard, 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(AUTHOR) +create.insertInto(AUTHOR) .set(AUTHOR.ID, 100) .set(AUTHOR.FIRST_NAME, "Hermann") .set(AUTHOR.LAST_NAME, "Hesse") .newRecord() .set(AUTHOR.ID, 101) .set(AUTHOR.FIRST_NAME, "Alfred") - .set(AUTHOR.LAST_NAME, "Döblin"); + .set(AUTHOR.LAST_NAME, "Döblin");

    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. Internally, the two syntaxes are strictly equivalent. @@ -2280,12 +2232,12 @@ SELECT 101, 'Alfred', 'Döblin' FROM DUAL; 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 (i.e. if they support the SQL standard ). Here is an example how to use the ON DUPLICATE KEY UPDATE clause:

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

    The synthetic ON DUPLICATE KEY IGNORE clause

    @@ -2293,18 +2245,18 @@ create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.LAST_NAME) 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 :

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

    Postgres's INSERT .. RETURNING

    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:

    - record = create.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .values("Charlotte", "Roche") @@ -2321,7 +2273,7 @@ create.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .values("Friedrich", "Schiller") // You can request any field. Also trigger-generated values .returning(AUTHOR.ID, AUTHOR.CREATION_DATE) - .fetch();]]> + .fetch();]]>

    Some databases have poor support for returning generated keys after INSERTs. In those cases, jOOQ might need to issue another in order to fetch an @@identity value. Be aware, that this can lead to race-conditions in those databases that cannot properly return generated ID values. For more information, please consider the jOOQ Javadoc for the returning() clause. @@ -2333,53 +2285,49 @@ create.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) In some occasions, you may prefer the INSERT SELECT syntax, for instance, when you copy records from one table to another:

    -create.insertInto(AUTHOR_ARCHIVE) - .select(create.selectFrom(AUTHOR).where(AUTHOR.DECEASED.isTrue())); - -
    +create.insertInto(AUTHOR_ARCHIVE) + .select(create.selectFrom(AUTHOR).where(AUTHOR.DECEASED.isTrue()));
    The UPDATE statement - +

    The UPDATE statement is used to modify one or several pre-existing records in a database table. UPDATE statements are only possible on single tables. Support for multi-table updates will be implemented in the near future. An example update query is given here:

    - + UPDATE AUTHOR SET FIRST_NAME = 'Hermann', LAST_NAME = 'Hesse' - WHERE ID = 3; -create.update(AUTHOR) + WHERE ID = 3;create.update(AUTHOR) .set(AUTHOR.FIRST_NAME, "Hermann") .set(AUTHOR.LAST_NAME, "Hesse") .where(AUTHOR.ID.equal(3)); - + -
    +
    The DELETE statement - +

    The DELETE statement physically removes records from a database table. DELETE statements are only possible on single tables. Support for multi-table deletes will be implemented in the near future. An example delete query is given here:

    - + DELETE AUTHOR - WHERE ID = 100; -create.delete(AUTHOR) + WHERE ID = 100;create.delete(AUTHOR) .where(AUTHOR.ID.equal(100)); - + -
    +
    The 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)

    @@ -2387,15 +2335,14 @@ create.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) 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 {jooq-version}, 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 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(AUTHOR) +WHEN NOT MATCHED THEN INSERT (LAST_NAME) VALUES ('Hitchcock')create.mergeInto(AUTHOR) .using(create().selectOne()) .on(AUTHOR.LAST_NAME.equal("Hitchcock")) .whenMatchedThenUpdate() @@ -2403,39 +2350,38 @@ WHEN NOT MATCHED THEN INSERT (LAST_NAME) VALUES ('Hitchcock') .whenNotMatchedThenInsert(AUTHOR.LAST_NAME) .values("Hitchcock"); - +

    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 AUTHOR (FIRST_NAME, LAST_NAME) KEY (LAST_NAME) -VALUES ('John', 'Hitchcock') -create.mergeInto(AUTHOR, +VALUES ('John', 'Hitchcock')create.mergeInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .key(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

    -
    +
    The TRUNCATE statement - +

    The TRUNCATE statement is the only DDL statement supported by jOOQ so far. It is popular in many databases when you want to bypass constraints for table truncation. Databases may behave differently, when a truncated table is referenced by other tables. For instance, they may fail if records from a truncated table are referenced, even with ON DELETE CASCADE clauses in place. Please, consider your database manual to learn more about its TRUNCATE implementation.

    @@ -2443,44 +2389,42 @@ VALUES ('John', 'Hitchcock') The TRUNCATE syntax is trivial:

    - - TRUNCATE TABLE AUTHOR; - create.truncate(AUTHOR).execute(); - + + TRUNCATE TABLE AUTHOR;create.truncate(AUTHOR).execute(); +

    TRUNCATE is not supported by Ingres and SQLite. jOOQ will execute a DELETE FROM AUTHOR statement instead.

    -
    +
    Table expressions - +

    The following sections explain the various types of table expressions supported by jOOQ

    -
    +
    Generated Tables - +

    Most of the times, when thinking about a you're probably thinking about an actual physical table in your database schema. If you're using jOOQ's , you will have all tables from your database schema available to you as type safe Java objects. You can then use these tables in SQL , or in other , just like any other table expression. An example is given here:

    - + - + .on(AUTHOR.ID.equal(BOOK.AUTHOR_ID));]]>

    The above example shows how AUTHOR and BOOK tables are joined in a . It also shows how you can access physical by dereferencing the relevant Java attributes of their tables. @@ -2488,17 +2432,17 @@ ON (AUTHOR.ID = BOOK.AUTHOR_ID)]]>

    See the manual's section about for more information about what is really generated by the

    -
    +
    Aliased Tables - +

    The strength of jOOQ's becomes more obvious when you perform table aliasing and dereference fields from generated aliased tables. This can best be shown by example:

    - 1920 AND a.first_name = 'Paulo' - ORDER BY b.title]]> - + .orderBy(b.TITLE);]]>

    As you can see in the above example, calling as() on generated tables returns an object of the same type as the table. This means that the resulting object can be used to dereference fields from the aliased table. This is quite powerful in terms of having your Java compiler check the syntax of your SQL statements. If you remove a column from a table, dereferencing that column from that table alias will cause compilation errors. @@ -2529,17 +2472,17 @@ create.select()

    TODO document this

    -
    +
    Joined tables - +

    The that can be used in are the most powerful and best supported means of creating new in SQL. Informally, the following can be said:

    -A(colA1, ..., colAn) "join" B(colB1, ..., colBm) "produces" C(colA1, ..., colAn, colB1, ..., colBm) +A(colA1, ..., colAn) "join" B(colB1, ..., colBm) "produces" C(colA1, ..., colAn, colB1, ..., colBm)

    SQL and relational algebra distinguish between at least the following JOIN types (upper-case: SQL, lower-case: relational algebra): @@ -2557,7 +2500,7 @@ create.select() jOOQ supports all of these JOIN types (except semi-join and anti-join) directly on any :

    - table) // Various overloaded INNER JOINs @@ -2580,41 +2523,40 @@ Table crossJoin(TableLike) // Various overloaded NATURAL JOINs Table naturalJoin(TableLike) Table naturalLeftOuterJoin(TableLike) -Table naturalRightOuterJoin(TableLike)]]> +Table naturalRightOuterJoin(TableLike)]]>

    Note that most of jOOQ's JOIN operations give way to a similar DSL API hierarchy as previously seen in the manual's section about the

    -
    +
    Nested SELECTs - +

    A can appear almost anywhere a can. Such a "nested SELECT" is often called a "derived table". Apart from many convenience methods accepting objects directly, a SELECT statement can always be transformed into a object using the asTable() method.

    Example: Scalar subquery

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

    Example: Derived table

    - + - nested = +]]> nested = create.select(BOOK.AUTHOR_ID, count().as("books")) .from(BOOK) .groupBy(BOOK.AUTHOR_ID).asTable("nested"); @@ -2633,10 +2574,10 @@ ORDER BY nested.books DESC create.select(nested.getFields()) .from(nested) .orderBy(nested.getField("books"));]]> - +

    Example: Correlated subquery

    - + - +]]> Field books = create.selectCount() .from(BOOK) @@ -2656,52 +2596,52 @@ Field books = create.select(AUTHOR.ID, books) .from(AUTHOR) .orderBy(books, AUTHOR.ID));]]> - - + +
    The Oracle 11g PIVOT clause - +

    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 .. +-- SELECT .. FROM table PIVOT (aggregateFunction [, aggregateFunction] FOR column IN (expression [, expression])) --- WHERE .. +-- WHERE ..

    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 slightly different PIVOT clause will be added later. Also, jOOQ may simulate PIVOT for other dialects in the future.

    -
    +
    jOOQ's relational division syntax - +

    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 +Assume the following cross join / cartesian product C = A × B Then it can be said that A = C ÷ B -B = C ÷ A +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) +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" +SELECT DISTINCT C.TEXT FROM C "c1" WHERE NOT EXISTS ( SELECT 1 FROM B WHERE NOT EXISTS ( @@ -2709,7 +2649,7 @@ WHERE NOT EXISTS ( 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. @@ -2723,13 +2663,13 @@ WHERE NOT EXISTS (

  • http://en.wikipedia.org/wiki/Relational_algebra#Division
  • http://www.simple-talk.com/sql/t-sql-programming/divided-we-stand-the-sql-of-relational-division/
  • -
    +
    Array and cursor unnesting - +

    The SQL standard specifies how SQL databases should implement ARRAY and TABLE types, as well as CURSOR types. Put simply, a CURSOR is a pointer to any materialised . Depending on the cursor's features, this table expression can be scrolled through in both directions, records can be locked, updated, removed, inserted, etc. Often, CURSOR types contain tuples, whereas ARRAY and TABLE types contain simple scalar values, although that is not a requirement

    @@ -2743,21 +2683,20 @@ WHERE NOT EXISTS ( The real power of these types become more obvious when you fetch them from to unnest them as and use them in your . An example is given here, where Oracle's DBMS_XPLAN package is used to fetch a cursor containing data about the most recent execution plan:

    - + - - +

    Note, in order to access the DbmsXplan package, you can use the to generate Oracle's SYS schema.

    -
    +
    The DUAL table - +

    The SQL standard specifies that the is optional in a . However, according to the standard, you may then no longer use some other clauses, such as the . In the real world, there exist three types of databases:

    @@ -2770,7 +2709,7 @@ FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(null, null, 'ALLSTATS'));]]> With jOOQ, you don't have to worry about the above distinction of SQL dialects. jOOQ never requires a FROM clause, but renders the necessary "DUAL" table, if needed. The following program shows how jOOQ renders "DUAL" tables

    - + - - +

    Note, that some databases (H2, MySQL) can normally do without "dual". However, there exist some corner-cases with complex nested SELECT statements, where this will cause syntax errors (or parser bugs). To stay on the safe side, jOOQ will always render "dual" in those dialects.

    -
    +
    Column expressions - +

    jOOQ allows you to freely create arbitrary column expressions using a fluent expression construction API. Many expressions can be formed as functions from , other expressions can be formed based on a pre-existing column expression. For example:

    - field1 = BOOK.TITLE; // A function created from the Factory using "prefix" notation @@ -2827,31 +2765,30 @@ Field field3 = BOOK.TITLE.trim(); // More complex function with advanced DSL syntax Field field4 = listAgg(BOOK.TITLE) .withinGroupOrderBy(BOOK.ID.asc()) - .over().partitionBy(AUTHOR.ID);]]> + .over().partitionBy(AUTHOR.ID);]]>

    In general, it is up to you whether you want to use the "prefix" notation or the "postfix" notation to create new column expressions based on existing ones. The "SQL way" would be to use the "prefix notation", with functions created from the . The "Java way" or "object-oriented way" would be to use the "postfix" notation with functions created from objects. Both ways ultimately create the same query part, though.

    -
    +
    Table columns - +

    Table columns are the most simple implementations of a . They are mainly produced by jOOQ's and can be dereferenced from the generated tables. This manual is full of examples involving table columns. Another example is given in this query:

    - + - - +

    Table columns implement a more specific interface called , which is parameterised with its associated <R extends Record> record type. @@ -2859,45 +2796,43 @@ ORDER BY BOOK.TITLE]]>

    See the manual's section about for more information about what is really generated by the

    -
    +
    Aliased columns - +

    Just like , columns can be renamed using aliases. Here is an example:

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

    Here is how it's done with jOOQ:

    -Record record = create.select( +Record record = create.select( concat(AUTHOR.FIRST_NAME, val(" "), AUTHOR.LAST_NAME).as("author"), count().as("books")) .from(AUTHOR) .join(BOOK).on(AUTHOR.ID.equal(BOOK.AUTHOR_ID)) - .groupBy(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME).fetchAny(); + .groupBy(AUTHOR.FIRST_NAME, 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")); - -
    +System.out.println("Author : " + record.getValue("author")); +System.out.println("Books : " + record.getValue("books"));
    Cast expressions - +

    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.

    @@ -2905,27 +2840,27 @@ System.out.println("Books : " + record.getValue("books")); Sometimes, this automatic mapping might not be what you needed, or jOOQ cannot know the type of a field. In those cases you would write SQL type CASTs like this:

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

    in jOOQ, you can write something like that:

    -create.select(TAuthor.LAST_NAME.cast(PostgresDataType.TEXT)); +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)); +create.select(TAuthor.LAST_NAME.cast(String.class));

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

    - { + { // Cast this field to the type of another field Field cast(Field field); @@ -2945,41 +2880,39 @@ public class Factory { Field castNull(Field field); Field castNull(DataType type); Field castNull(Class type); -}]]> -
    +}]]>
    Arithmetic expressions - +

    Numeric arithmetic expressions

    Your database can do the math for you. 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 +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); +create.select(val(1).add(2).mul(val(5).sub(3)).div(2).mod(10);

    Datetime arithmetic expressions

    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)); - + + 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: @@ -2988,31 +2921,30 @@ public class Factory {

  • INTERVAL YEAR TO MONTH:
  • INTERVAL DAY TO SECOND:
  • -
    +
    String concatenation - +

    The SQL standard defines the concatenation operator to be an infix operator, similar to the ones we've seen in the chapter about . This operator looks like this: ||. Some other dialects do not support this operator, but expect a concat() function, instead. jOOQ renders the right operator / function, depending on your :

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

    There are a variety of general functions supported by jOOQ As discussed in the chapter about functions are mostly simulated in your database, in case they are not natively supported.

    @@ -3029,12 +2961,12 @@ create.select(concat("A", "B", "C"));

    Please refer to the for more details.

    -
    +
    Numeric functions - +

    Math can be done efficiently in the database before returning results to your Java application. In addition to the discussed previously, jOOQ also supports a variety of numeric functions. As discussed in the chapter about numeric functions (as any function type) are mostly simulated in your database, in case they are not natively supported.

    @@ -3076,12 +3008,12 @@ create.select(concat("A", "B", "C"));

    Please refer to the for more details.

    -
    +
    Bitwise functions - +

    Interestingly, bitwise functions and bitwise arithmetic is not very popular among SQL databases. Most databases only support a few bitwise operations, while others ship with the full set of operators. jOOQ's API includes most bitwise operations as listed below. In order to avoid ambiguities with , all bitwise functions are prefixed with "bit"

    @@ -3104,12 +3036,12 @@ create.select(concat("A", "B", "C")); http://blog.jooq.org/2011/10/30/the-comprehensive-sql-bitwise-operations-compatibility-list/

    -
    +
    String functions - +

    String formatting can be done efficiently in the database before returning results to your Java application. As discussed in the chapter about string functions (as any function type) are mostly simulated in your database, in case they are not natively supported.

    @@ -3147,18 +3079,18 @@ create.select(concat("A", "B", "C")); Various databases have some means of searching through columns using regular expressions if the does not provide sufficient pattern matching power. While there are many different functions and operators in the various databases, jOOQ settled for the SQL:2008 standard REGEX_LIKE operator. Being an operator (and not a function), you should use the corresponding method on :

    - +

    Note that the SQL standard specifies that patterns should follow the XQuery standards. In the real world, the POSIX regular expression standard is the most used one, some use Java regular expressions, and only a few ones use Perl regular expressions. jOOQ does not make any assumptions about regular expression syntax. For cross-database compatibility, please read the relevant database manuals carefully, to learn about the appropriate syntax. Please refer to the for more details.

    -
    +
    Date and time functions - +

    This is a list of date and time functions supported by jOOQ's :

    @@ -3177,29 +3109,29 @@ create.select(concat("A", "B", "C"));

    jOOQ fills a gap opened by JDBC, which neglects an important SQL data type as defined by the SQL standards: INTERVAL types. See the manual's section about for more details.

    -
    +
    System functions - +

    This is a list of system functions supported by jOOQ's :

    • CURRENT_USER: Get current user.
    -
    +
    Aggregate functions - +

    Aggregate functions work just like functions, even if they have a slightly different semantics. Here are some example aggregate functions from the :

    - count(); AggregateFunction count(Field field); AggregateFunction max(Field field); @@ -3225,20 +3157,19 @@ AggregateFunction median(Field field); AggregateFunction stddevPop(Field field); AggregateFunction stddevSamp(Field field); AggregateFunction varPop(Field field); -AggregateFunction varSamp(Field field);]]> +AggregateFunction varSamp(Field field);]]>

    Here's an example, counting the number of books any author has written:

    - + SELECT AUTHOR_ID, COUNT(*) FROM BOOK -GROUP BY AUTHOR_ID -create.select(BOOK.AUTHOR_ID, count()) +GROUP BY AUTHOR_IDcreate.select(BOOK.AUTHOR_ID, count()) .from(BOOK) .groupBy(BOOK.AUTHOR_ID); - +

    Aggregate functions have strong limitations about when they may be used and when not. For instance, you can use aggregate functions in scalar queries. Typically, this means you only select aggregate functions, no or other . Another use case is to use them along with a as seen in the previous example. Note, that jOOQ does not check whether your using of aggregate functions is correct according to the SQL standards, or according to your database's behaviour. @@ -3248,39 +3179,37 @@ GROUP BY AUTHOR_ID

    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 Oracle's LISTAGG() (also known as GROUP_CONCAT in other ). 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, ", ") +GROUP BY AUTHOR_IDcreate.select(listAgg(BOOK.TITLE, ", ") .withinGroupOrderBy(BOOK.TITLE)) .from(BOOK) .groupBy(BOOK.AUTHOR_ID) - +

    The above query might yield:

    -+---------------------+ ++---------------------+ | LISTAGG | +---------------------+ | 1984, Animal Farm | | O Alquimista, Brida | -+---------------------+ ++---------------------+

    FIRST and LAST: Oracle's "ranked" aggregate functions

    Oracle allows for restricting aggregate functions using the KEEP() clause, which is supported by jOOQ. In Oracle, some aggregate functions (MIN, MAX, SUM, AVG, COUNT, VARIANCE, or STDDEV) can be restricted by this clause, hence also allows for specifying it. Here are a couple of examples using this clause:

    - + SUM(BOOK.AMOUNT_SOLD) - KEEP(DENSE_RANK FIRST ORDER BY BOOK.AUTHOR_ID) -sum(BOOK.AMOUNT_SOLD) + KEEP(DENSE_RANK FIRST ORDER BY BOOK.AUTHOR_ID)sum(BOOK.AMOUNT_SOLD) .keepDenseRankFirstOrderBy(BOOK.AUTHOR_ID) - +

    User-defined aggregate functions

    @@ -3291,12 +3220,12 @@ GROUP BY AUTHOR_ID

    In those databases that support , jOOQ's can be transformed into a window function / analytical function by calling over() on it. See the manual's section about for more details.

    -
    +
    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. Note, that H2 and HSQLDB have implemented ROW_NUMBER() functions, without true windowing support.

    @@ -3304,7 +3233,7 @@ GROUP BY AUTHOR_ID As previously discussed, any can be transformed into a window function using the over() method. See the chapter about for details. In addition to those, there are also some more window functions supported by jOOQ, as declared in the :

    - rowNumber(); WindowOverStep rank(); WindowOverStep denseRank(); @@ -3324,7 +3253,7 @@ GROUP BY AUTHOR_ID // Statistical functions WindowOverStep cumeDist(); - WindowOverStep ntile(int number);]]> + WindowOverStep ntile(int number);]]>

    SQL distinguishes between various window function types (e.g. "ranking functions"). Depending on the function, SQL expects mandatory PARTITION BY or ORDER BY clauses within the OVER() clause. jOOQ does not enforce those rules for two reasons: @@ -3341,7 +3270,7 @@ GROUP BY AUTHOR_ID Here are some simple examples of window functions with jOOQ:

    - + -- Sample uses of ROW_NUMBER() ROW_NUMBER() OVER() ROW_NUMBER() OVER(PARTITION BY 1) @@ -3352,8 +3281,7 @@ ROW_NUMBER() OVER(PARTITION BY BOOK.AUTHOR_ID ORDER BY BOOK.ID) FIRST_VALUE(BOOK.ID) OVER() FIRST_VALUE(BOOK.ID IGNORE NULLS) OVER() FIRST_VALUE(BOOK.ID RESPECT NULLS) OVER() - -// Sample uses of rowNumber() +// Sample uses of rowNumber() rowNumber().over() rowNumber().over().partitionByOne() rowNumber().over().partitionBy(BOOK.AUTHOR_ID) @@ -3364,27 +3292,26 @@ firstValue(BOOK.ID).over() firstValue(BOOK.ID).ignoreNulls().over() firstValue(BOOK.ID).respectNulls().over() - +

    An advanced window function example

    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). Window functions are accessible from the previously seen 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, + FROM transactionscreate.select(t.BOOKED_AT, t.AMOUNT, sum(t.AMOUNT).over().partitionByOne() .orderBy(t.BOOKED_AT) .rowsBetweenUnboundedPreceding() .andCurrentRow().as("total") .from(TRANSACTIONS.as("t")); - +

    Window functions created from ordered aggregate functions

    @@ -3392,48 +3319,46 @@ firstValue(BOOK.ID).respectNulls().over() In the previous chapter about , we have seen the concept of "ordered aggregate functions", such as Oracle's LISTAGG(). These functions have a window function / analytical function variant, as well. For example:

    - + SELECT LISTAGG(TITLE, ', ') WITHIN GROUP (ORDER BY TITLE) OVER (PARTITION BY BOOK.AUTHOR_ID) -FROM BOOK -create.select(listAgg(BOOK.TITLE, ", ") +FROM BOOKcreate.select(listAgg(BOOK.TITLE, ", ") .withinGroupOrderBy(BOOK.TITLE) .over().partitionBy(BOOK.AUTHOR_ID)) .from(BOOK) - +

    Window functions created from Oracle's FIRST and LAST aggregate functions

    In the previous chapter about , we have seen the concept of "FIRST and LAST aggregate functions". These functions have a window function / analytical function variant, as well. For example:

    - + SUM(BOOK.AMOUNT_SOLD) KEEP(DENSE_RANK FIRST ORDER BY BOOK.AUTHOR_ID) - OVER(PARTITION BY 1) -sum(BOOK.AMOUNT_SOLD) + OVER(PARTITION BY 1)sum(BOOK.AMOUNT_SOLD) .keepDenseRankFirstOrderBy(BOOK.AUTHOR_ID) .over().partitionByOne() - +

    Window functions created from user-defined aggregate functions

    User-defined aggregate functions also implement , hence they can also be transformed into window functions using over(). This is supported by Oracle in particular. See the manual's section about for more details.

    -
    +
    Grouping functions - +

    ROLLUP() explained in SQL

    The SQL standard defines special functions that can be used in the : the grouping functions. These functions can be used to generate several groupings in a single clause. This can best be explained in SQL. Let's take ROLLUP() for instance:

    - + - - +

    In English, the ROLLUP() grouping function provides N+1 groupings, when N is the number of arguments to the ROLLUP() function. Each grouping has an additional group field from the ROLLUP() argument field list. The results of the second query might look something like this:

    - ++-----------+--------------+----------+]]>

    CUBE() explained in SQL

    CUBE() is different from ROLLUP() in the way that it doesn't just create N+1 groupings, it creates all 2^N possible combinations between all group fields in the CUBE() function argument list. Let's re-consider our second query from before:

    - + - - +

    The results would then hold:

    - ++-----------+--------------+----------+]]>

    GROUPING SETS()

    @@ -3562,7 +3485,7 @@ ORDER BY 1 NULLS FIRST, 2 NULLS FIRST jOOQ fully supports all of these functions, as well as the utility functions GROUPING() and GROUPING_ID(), used for identifying the grouping set ID of a record. The thus includes:

    - rollup(Field... fields); Field cube(Field... fields); Field groupingSets(Field... fields); @@ -3571,66 +3494,64 @@ Field groupingSets(Collection>... fields); // The utility functions generating IDs per GROUPING SET Field grouping(Field); -Field groupingId(Field...);]]> +Field groupingId(Field...);]]>

    MySQL's and CUBRID's WITH ROLLUP syntax

    MySQL and CUBRID don't know any grouping functions, but they support a WITH ROLLUP clause, that is equivalent to simple ROLLUP() grouping functions. jOOQ simulates ROLLUP() in MySQL and CUBRID, by rendering this WITH ROLLUP clause. The following two statements mean the same:

    - + - - -
    + +
    User-defined functions - +

    Some databases support user-defined functions, which can be embedded in any SQL statement, if you're using jOOQ's . Let's say you have the following simple function in Oracle SQL:

    - +]]>

    The above function will be made available from a generated class. You can use it like any other :

    - - - - + + +

    Note that user-defined functions returning or data types can also be used wherever can be used, if they are

    -
    +
    User-defined aggregate functions - +

    Some databases support user-defined aggregate functions, which can then be used along with or as . An example for such a database is Oracle. With Oracle, you can define the following OBJECT type (the example was taken from the Oracle 11g documentation):

    - +END;]]>

    The above OBJECT type is then available to function declarations as such:

    - +PARALLEL_ENABLE AGGREGATE USING U_SECOND_MAX;]]>

    Using the generated aggregate function

    jOOQ's will detect such aggregate functions and generate them differently from regular . They implement the type, as mentioned in the manual's section about . Here's how you can use the SECOND_MAX() aggregate function with jOOQ:

    - + - - -
    + +
    The CASE expression - +

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

    - + - - +

    In jOOQ, both syntaxes are supported (The second one is simulated in Derby, which only knows the first one). 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. @@ -3747,15 +3666,15 @@ create.decode().value(AUTHOR.FIRST_NAME) A CASE expression can be used anywhere where you can place a . For instance, you can SELECT the above expression, if you're selecting from AUTHOR:

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

    The Oracle DECODE() function

    Oracle knows a more succinct, but maybe less readable DECODE() function with a variable number of arguments. This function roughly does the same as the second case expression syntax. jOOQ supports the DECODE() function and simulates it using CASE expressions in all dialects other than Oracle:

    - + - - +

    CASE clauses in an ORDER BY clause

    Sort indirection is often implemented with a CASE clause of a SELECT's ORDER BY clause. See the manual's section about the for more details.

    -
    +
    Sequences and serials - +

    Sequences implement the interface, providing essentially this functionality:

    - currval(); // Get a field for the NEXTVAL sequence property -Field nextval();]]> +Field nextval();]]>

    So if you have a sequence like this in Oracle:

    -CREATE SEQUENCE s_author_id +CREATE SEQUENCE s_author_id

    You can then use your object directly in a SQL statement as such:

    - +]]>
    • For more information about generated sequences, refer to the manual's section about
    • For more information about executing standalone calls to sequences, refer to the manual's section about
    -
    +
    Conditional expressions - +

    Conditions or conditional expressions are widely used in SQL and in the jOOQ API. They can be used in

    @@ -3865,22 +3783,21 @@ create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)

    Note that jOOQ does not model these values as actual compatible.

    -
    +
    Condition building - +

    With jOOQ, most are built from , calling various methods on them. For instance, to build a , you can write the following expression:

    - + - - +

    Create conditions from the Factory

    @@ -3896,48 +3813,47 @@ BOOK.TITLE.notEqual("Animal Farm")]]>

    Conditions can also be connected using as will be discussed in a subsequent chapter.

    -
    +
    AND, OR, NOT boolean operators - +

    In SQL, as in most other languages, can be connected using the AND and OR binary operators, as well as the NOT unary operator, to form new conditional expressions. In jOOQ, this is modelled as such:

    - + - - +

    The above example shows that the number of parentheses in Java can quickly explode. Proper indentation may become crucial in making such code readable. In order to understand how jOOQ composes combined conditional expressions, let's assign component expressions first:

    - +Condition combined2 = combined1.andNot(c); // The left-hand side of the AND NOT () operator is already wrapped in parentheses]]>

    The Condition API

    Here are all boolean operators on the interface:

    -) // Combine conditions with OR. Convenience for adding orNot(Condition) // Combine conditions with OR. Convenience for adding an inverted condition to the rhs orNotExists(Select) // Combine conditions with OR. Convenience for adding an inverted exists predicate to the rhs -not() // Invert a condition (synonym for Factory.not(Condition)]]> -
    +not() // Invert a condition (synonym for Factory.not(Condition)]]>
    Comparison predicate - +

    In SQL, comparison predicates are formed using common comparison operators:

    @@ -3976,7 +3891,7 @@ not() // Invert a condition (synonym for Factory.not(Conditi Unfortunately, Java does not support operator overloading, hence these operators are also implemented as methods in jOOQ, like any other SQL syntax elements. The relevant parts of the interface are these:

    -); // = (some column expression) eq or equal(Select); // = (some scalar SELECT statement) ne or notEqual(T); // <> (some bind value) @@ -3993,7 +3908,7 @@ gt or greaterThan(Field); // > (some column expression) gt or greaterThan(Select); // > (some scalar SELECT statement) ge or greaterOrEqual(T); // >= (some bind value) ge or greaterOrEqual(Field); // >= (some column expression) -ge or greaterOrEqual(Select); // >= (some scalar SELECT statement)]]> +ge or greaterOrEqual(Select); // >= (some scalar SELECT statement)]]>

    Note that every operator is represented by two methods. A verbose one (such as equal()) and a two-character one (such as eq()). Both methods are the same. You may choose either one, depending on your taste. The manual will always use the more verbose one. @@ -4009,30 +3924,28 @@ ge or greaterOrEqual(Select); // >= (some scalar SELECT statement)]]> In addition to the above, jOOQ provides a few convenience methods for common operations performed on strings using comparison predicates:

    - + LOWER('animal farm')]]> - LOWER('animal farm')]]> - -
    + +
    Quantified comparison predicate - +

    If the right-hand side of a turns out to be a non-scalar table subquery, you can wrap that subquery in a quantifier, such as ALL, ANY, or SOME. Note that the SQL standard defines ANY and SOME to be equivalent. jOOQ settled for the more intuitive ANY and doesn't support SOME. Here are some examples, supported by jOOQ:

    - + ALL(1920, 1940)]]> - ALL(1920, 1940)]]> - +

    For the example, the right-hand side of the quantified comparison predicates were filled with argument lists. But it is easy to imagine that the source of values results from a . @@ -4043,37 +3956,35 @@ BOOK.PUBLISHED_IN.greaterThanAll(1920, 1940);]]> It is interesting to note that the SQL standard defines the in terms of the ANY-quantified predicate. The following two expressions are equivalent:

    - - - - + + +

    Typically, the is more readable than the quantified comparison predicate.

    -
    +
    NULL predicate - +

    In SQL, you cannot compare NULL with any value using , as the result would yield NULL again, which is neither TRUE nor FALSE (see also the manual's section about ). In order to test a for NULL, use the NULL predicate as such:

    - + - - + -
    +
    DISTINCT predicate - +

    Some databases support the DISTINCT predicate, which serves as a convenient, NULL-safe . With the DISTINCT predicate, the following truth table can be assumed:

    @@ -4087,18 +3998,17 @@ BOOK.TITLE.isNotNull()]]> For instance, you can compare two fields for distinctness, ignoring the fact that any of the two could be NULL, which would lead to funny results. This is supported by jOOQ as such:

    - + - - +

    If your database does not natively support the DISTINCT predicate, jOOQ simulates it with an equivalent , modelling the above truth table:

    - + - - -
    + +
    BETWEEN predicate - +

    The BETWEEN predicate can be seen as syntactic sugar for a pair of . According to the SQL standard, the following two predicates are equivalent:

    - - -= [B] AND [A] <= [C]]]> - + += [B] AND [A] <= [C]]]> +

    Note the inclusiveness of range boundaries in the definition of the BETWEEN predicate. Intuitively, this is supported in jOOQ as such:

    - + - - +

    BETWEEN SYMMETRIC

    The SQL standard defines the SYMMETRIC keyword to be used along with BETWEEN to indicate that you do not care which bound of the range is larger than the other. A database system should simply swap range bounds, in case the first bound is greater than the second one. jOOQ supports this keyword as well, simulating it if necessary.

    - + - - +

    The simulation is done trivially:

    - - - - + + + -
    +
    LIKE predicate - +

    LIKE predicates are popular for simple wildcard-enabled pattern matching. Supported wildcards in all SQL databases are:

    @@ -4180,24 +4085,22 @@ BOOK.PUBLISHED_IN.notBetweenSymmetric(1940, 1920)]]> With jOOQ, the LIKE predicate can be created from any as such:

    - + - - +

    Escaping operands with the LIKE predicate

    Often, your pattern may contain any of the wildcard characters "_" and "%", in case of which you may want to escape them. jOOQ does not automatically escape patterns in like() and notLike() methods. Instead, you can explicitly define an escape character as such:

    - + - - +

    In the above predicate expressions, the exclamation mark character is passed as the escape character to escape wildcard characters "!_" and "!%", as well as to escape the escape character itself: "!!" @@ -4211,7 +4114,7 @@ BOOK.TITLE.notLike("%The !%-Sign Book%", '!')]]> In addition to the above, jOOQ provides a few convenience methods for common operations performed on strings using the LIKE predicate. Typical operations are "contains predicates", "starts with predicates", "ends with predicates", etc. Here is the full convenience API wrapping LIKE predicates:

    - + - - +

    Note, that jOOQ escapes % and _ characters in value in some of the above predicate implementations. For simplicity, this has been omitted in this manual.

    -
    +
    IN predicate - +

    In SQL, apart from comparing a value against several values, the IN predicate can be used to create semi-joins or anti-joins. jOOQ knows the following methods on the interface, to construct such IN predicates:

    -) // Construct an IN predicate from a collection of bind values +) // Construct an IN predicate from a collection of bind values in(T...) // Construct an IN predicate from bind values in(Field...) // Construct an IN predicate from column expressions in(Select) // Construct an IN predicate from a subselect notIn(Collection) // Construct a NOT IN predicate from a collection of bind values notIn(T...) // Construct a NOT IN predicate from bind values notIn(Field...) // Construct a NOT IN predicate from column expressions -notIn(Select) // Construct a NOT IN predicate from a subselect]]> +notIn(Select) // Construct a NOT IN predicate from a subselect]]>

    A sample IN predicate might look like this:

    - + - - +

    NOT IN and NULL values

    @@ -4269,7 +4170,7 @@ BOOK.TITLE.notIn("Animal Farm", "1984")]]> Beware that you should probably not have any NULL values in the right hand side of a NOT IN predicate, as the whole expression would evaluate to NULL, which is rarely desired. This can be shown informally using the following reasoning:

    --- The following conditional expressions are formally or informally equivalent +-- The following conditional expressions are formally or informally equivalent A NOT IN (B, C) A != ANY(B, C) A != B AND A != C @@ -4278,17 +4179,17 @@ A != B AND A != C A NOT IN (B, NULL) -- Substitute C for NULL A != B AND A != NULL -- From the above rules A != B AND NULL -- [ANY] != NULL yields NULL -NULL -- [ANY] AND NULL yields NULL +NULL -- [ANY] AND NULL yields NULL

    A good way to prevent this from happening is to use the for anti-joins, which is NULL-value insensitive. See the manual's section about to see a boolean truth table.

    -
    +
    EXISTS predicate - +

    Slightly less intuitive, yet more powerful than the previously discussed is the EXISTS predicate, that can be used to form semi-joins or anti-joins. With jOOQ, the EXISTS predicate can be formed in various ways:

    @@ -4302,16 +4203,15 @@ NULL -- [ANY] AND NULL yields NULL An example of an EXISTS predicate can be seen here:

    - + - - +

    Note that in SQL, the projection of a subselect in an EXISTS predicate is irrelevant. To help you write queries like the above, you can use jOOQ's selectZero() or selectOne() methods @@ -4322,14 +4222,14 @@ notExists(create.selectOne().from(BOOK) In theory, the two types of predicates can perform equally well. If your database system ships with a sophisticated cost-based optimiser, it will be able to transform one predicate into the other, if you have all necessary constraints set (e.g. referential constraints, not null constraints). However, in reality, performance between the two might differ substantially. An interesting blog post investigating this topic on the MySQL database can be seen here:
    http://blog.jooq.org/2012/07/27/not-in-vs-not-exists-vs-left-join-is-null-mysql/

    -
    +
    Plain SQL - +

    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 a host language (Java in this case), which was not made for exactly the same purposes as its hosted 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 by language constraints of its host language. We have seen many functionalities where the DSL becomes a bit verbose. This can be especially true for:

    @@ -4358,7 +4258,7 @@ notExists(create.selectOne().from(BOOK)

    Plain SQL API methods are usually overloaded in three ways. Let's look at the condition query part constructor:

    - +Condition condition(String sql, QueryPart... parts);]]>

    Please refer to the Javadoc for more details. The following is a more complete listing of plain SQL construction methods from the Factory:

    - resultQuery(String sql, QueryPart... parts); // A query with results. This is the same as resultQuery(...).fetch(); Result fetch(String sql); Result fetch(String sql, Object... bindings); -Result fetch(String sql, QueryPart... parts);]]> +Result fetch(String sql, QueryPart... parts);]]>

    Apart from the general factory methods, plain SQL is also available 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"); @@ -4454,7 +4354,7 @@ create.select(LAST_NAME, COUNT1, COUNT2) // Use plain SQL again as fields in GROUP BY and ORDER BY clauses .groupBy(LAST_NAME) - .orderBy(LAST_NAME);]]> + .orderBy(LAST_NAME);]]>

    Important things to note about plain SQL!

    @@ -4466,12 +4366,12 @@ create.select(LAST_NAME, COUNT1, COUNT2)

  • 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.
  • -
    +
    Bind values and parameters - +

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

    @@ -4490,31 +4390,31 @@ create.select(LAST_NAME, COUNT1, COUNT2)

    The following sections explain how you can introduce bind values in jOOQ, and how you can control the way they are rendered and bound to SQL.

    -
    +
    Indexed parameters - +

    JDBC only knows indexed bind values. A typical example for using bind values with JDBC is this:

    - +stmm.executeQuery();]]>

    With dynamic SQL, keeping track of the number of question marks and their corresponding index may turn out to be hard. jOOQ abstracts this and lets you provide the bind value right where it is needed. A trivial example is this:

    - +create.select().from(BOOK).where(BOOK.ID.equal(val(5))).and(BOOK.TITLE.equal(val("Animal Farm")));]]>

    Note the using of to explicitly create an indexed bind value. You don't have to worry about that index. When the query is , each bind value will render a question mark. When the query , each bind value will generate the appropriate bind value index. @@ -4525,7 +4425,7 @@ create.select().from(BOOK).where(BOOK.ID.equal(val(5))).and(BOOK.TITLE.equal(val Should you decide to run the above query outside of jOOQ, using your own , you can do so as follows:

    - select = create.select().from(BOOK).where(BOOK.ID.equal(5)).and(BOOK.TITLE.equal("Animal Farm")); + select = create.select().from(BOOK).where(BOOK.ID.equal(5)).and(BOOK.TITLE.equal("Animal Farm")); // Render the SQL statement: String sql = select.getSQL(); @@ -4535,34 +4435,34 @@ assertEquals("SELECT * FROM BOOK WHERE ID = ? AND TITLE = ?", sql); List values = select.getBindValues(); assertEquals(2, values.size()); assertEquals(5, values.get(0)); -assertEquals("Animal Farm", values.get(1));]]> +assertEquals("Animal Farm", values.get(1));]]>

    You can also extract specific bind values by index from a query, if you wish to modify their underlying value after creating a query. This can be achieved as such:

    - select = create.select().from(BOOK).where(BOOK.ID.equal(5)).and(BOOK.TITLE.equal("Animal Farm")); + select = create.select().from(BOOK).where(BOOK.ID.equal(5)).and(BOOK.TITLE.equal("Animal Farm")); Param param = select.getParam("2"); // You could now modify the Query's underlying bind value: if ("Animal Farm".equals(param.getValue())) { param.setConverted("1984"); -}]]> +}]]>

    For more details about jOOQ's internals, see the manual's section about .

    - +
    Named parameters - +

    Some SQL access abstractions that are built on top of JDBC, or some that bypass JDBC may support named parameters. jOOQ allows you to give names to your parameters as well, although those names are not rendered to SQL strings by default. Here is an example of how to create named parameters using the type:

    - param1 = query.getParam("lastName"); @@ -4571,41 +4471,40 @@ Param param2 = param("lastName", "Poe"); Query query2 = create.select().from(AUTHOR).where(LAST_NAME.equal(param2)); // You can now change the bind value directly on the Param reference: -param2.setValue("Orwell");]]> +param2.setValue("Orwell");]]>

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

    - +query2.bind("lastName", "Orwell");]]>

    In order to actually render named parameter names in generated SQL, use the method:

    - + - - -
    + +
    Inlined parameters - +

    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:

    @@ -4621,7 +4520,7 @@ WHERE LAST_NAME = :lastName]]> In both cases, your inlined bind values will be properly escaped to avoid SQL syntax errors and SQL injection. Some examples:

    - -
    + .where(LAST_NAME.equal("Poe"));]]>
    SQL injection and plain SQL QueryParts - +

    Special care needs to be taken when using . While jOOQ's API allows you to specify bind values for use with plain SQL, you're not forced to do that. For instance, both of the following queries will lead to the same, valid result:

    - +create.fetch("SELECT * FROM BOOK WHERE ID = 5 AND TITLE = 'Animal Farm'");]]>

    All methods in the jOOQ API that allow for plain (unescaped, untreated) SQL contain a warning message in their relevant Javadoc, to remind you of the risk of SQL injection in what is otherwise a SQL-injection-safe API.

    -
    +
    QueryParts - +

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

    @@ -4683,12 +4581,12 @@ create.fetch("SELECT * FROM BOOK WHERE ID = 5 AND TITLE = 'Animal Farm'");]]> The following sections explain some more details about and , as well as other implementation details about QueryParts in general.

    -
    +
    SQL rendering - +

    Every must implement the method to render its SQL string to a . This RenderContext has two purposes:

    @@ -4700,7 +4598,7 @@ create.fetch("SELECT * FROM BOOK WHERE ID = 5 AND TITLE = 'Animal Farm'");]]> API is given here:

    - +RenderContext castModeSome(SQLDialect... dialects);]]>

    The following additional methods are inherited from a common , which is shared among and :

    - +int peekIndex();]]>

    An example of rendering SQL

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

    --- [...] +-- [...] FROM AUTHOR JOIN BOOK ON AUTHOR.ID = BOOK.AUTHOR_ID --- [...] +-- [...]

    This is how jOOQ renders such a condition:

    - +}]]>

    See the manual's sections about and to learn about how to write your own query parts in order to extend jOOQ.

    -
    +
    Variable binding - +

    Every must implement the method. This BindContext has two purposes:

    @@ -4823,7 +4721,7 @@ public final void toSQL(RenderContext context) { An overview of the API is given here:

    - type) throws DataAccessException; -BindContext bindValues(Object... values) throws DataAccessException;]]> +BindContext bindValues(Object... values) throws DataAccessException;]]>

    Some additional methods are inherited from a common , which is shared among and . Details are documented in the previous chapter about @@ -4844,43 +4742,43 @@ BindContext bindValues(Object... values) throws DataAccessException;]]> A simple example can be provided by checking out jOOQ's internal representation of a (simplified) . It is used for any comparing two fields as for example the AUTHOR.ID = BOOK.AUTHOR_ID condition here:

    --- [...] +-- [...] WHERE AUTHOR.ID = ? --- [...] +-- [...]

    This is how jOOQ binds values on such a condition:

    - +}]]>

    See the manual's sections about and to learn about how to write your own query parts in order to extend jOOQ.

    -
    +
    Extend jOOQ with custom types - +

    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:

    - extends AbstractField {} + extends AbstractField {} public abstract class CustomCondition extends AbstractCondition {} public abstract class CustomTable> extends TableImpl {} -public abstract class CustomRecord> extends TableRecordImpl {}]]> +public abstract class CustomRecord> extends TableRecordImpl {}]]>

    These classes are declared public and covered by jOOQ's integration tests. When you extend these classes, you will have to provide your own implementations for the and methods, as discussed before:

    - +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. Here's an example showing how to create a field multiplying another field by 2

    - IDx2 = new CustomField(BOOK.ID.getName(), BOOK.ID.getDataType()) { @Override public void toSQL(RenderContext context) { @@ -4930,13 +4828,12 @@ final Field IDx2 = new CustomField(BOOK.ID.getName(), BOOK.ID. }; // Use the above field in a SQL statement: -create.select(IDx2).from(BOOK);]]> -
    +create.select(IDx2).from(BOOK);]]>
    Plain SQL QueryParts - +

    If you don't need the 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. Plain SQL methods in jOOQ's API come in two flavours.

    @@ -4948,29 +4845,29 @@ create.select(IDx2).from(BOOK);]]> The above distinction is best explained using an example:

    - id = val(5); Field title = val("Animal Farm"); -create.selectFrom(BOOK).where("BOOK.ID = {0} AND TITLE = {1}", id, title);]]> +create.selectFrom(BOOK).where("BOOK.ID = {0} AND TITLE = {1}", id, title);]]>

    The above technique allows for creating rather complex SQL clauses that are currently not supported by jOOQ, without extending any of the as indicated in the previous chapter.

    -
    +
    Serializability - +

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

    - select = (Select) in.readObject(); @@ -4979,13 +4876,13 @@ select.execute(); // In order to execute the above select, attach it first Factory create = new Factory(connection, SQLDialect.ORACLE); -create.attach(select);]]> +create.attach(select);]]>

    Automatically attaching QueryParts

    Another way of attaching QueryParts automatically, or rather providing them with a new at will, is to hook into the . More details about this can be found in the manual's chapter about

    -
    +
    @@ -4994,7 +4891,7 @@ create.attach(select);]]>
    SQL execution - +

    In a previous section of the manual, we've seen how jOOQ can be used to that can be executed with any API including JDBC or ... jOOQ. This section of the manual deals with various means of actually executing SQL with jOOQ.

    @@ -5019,12 +4916,12 @@ create.attach(select);]]>

    The following sections of this manual will show how jOOQ is wrapping JDBC for SQL execution

    -
    +
    Comparison between jOOQ and JDBC - +

    Similarities with JDBC

    Even if there are , there are a lot of similarities between JDBC and jOOQ. Just to name a few: @@ -5045,29 +4942,28 @@ create.attach(select);]]>

  • : If you want more fine-grained control over how many records are fetched into memory at once, you can still do that using jOOQ's feature
  • : jOOQ does not formally distinguish between static statements and prepared statements. By default, all statements are prepared statements in jOOQ, internally. Executing a statement as a static statement can be done simply using a
  • -
    +
    Query vs. ResultQuery - +

    Unlike JDBC, jOOQ has a lot of knowledge about a SQL query's structure and internals (see the manual's section about ). Hence, jOOQ distinguishes between these two fundamental types of queries. While every can be executed, only can return results (see the manual's section about to learn more about fetching results). With plain SQL, the distinction can be made clear most easily:

    - resultQuery = create.resultQuery("SELECT * FROM BOOK"); -Result resultQuery.fetch();]]> -
    +Result resultQuery.fetch();]]>
    Fetching - +

    Fetching is something that has been completely neglegted by JDBC and also by various other database abstraction libraries. Fetching is much more than just looping or listing records or mapped objects. There are so many ways you may want to fetch data from a database, it should be considered a first-class feature of any database abstraction API. Just to name a few, here are some of jOOQ's fetching modes:

    @@ -5091,7 +4987,7 @@ Result resultQuery.fetch();]]> These modes of fetching are also documented in subsequent sections of the manual

    - fetch(); // The "standard" fetch when you know your query returns only one record @@ -5115,14 +5011,14 @@ List> fetchMany(); > H fetchInto(H handler); // Execute a ResultQuery with jOOQ, but return a JDBC ResultSet, not a jOOQ object -ResultSet fetchResultSet();]]> +ResultSet fetchResultSet();]]>

    Fetch convenience

    These means of fetching are also available from and APIs

    - List fetch(Field field); List fetch(Field field, Class type); @@ -5156,14 +5052,14 @@ ResultSet fetchResultSet();]]> U fetchOne(int fieldIndex, Converter converter); Object fetchOne(String fieldName); T fetchOne(String fieldName, Class type); - U fetchOne(String fieldName, Converter converter);]]> + U fetchOne(String fieldName, Converter converter);]]>

    Fetch transformations

    These means of fetching are also available from and APIs

    - List fetchInto(Class type), MappingException; // Transform your records into another table type - Result fetchInto(Table table);]]> + Result fetchInto(Table table);]]>

    Note, that apart from the methods, all fetch() methods will immediately close underlying JDBC result sets.

    -
    +
    Record vs. TableRecord - +

    jOOQ understands that SQL is much more expressive than Java, when it comes to the declarative typing of . As a declarative language, SQL allows for creating ad-hoc tuples (records with indexed columns) and records (records with named columns). In Java, this is not possible to the same extent. Yet, still, sometimes you wish to use strongly typed records, when you know that you're selecting only from a single table

    @@ -5201,12 +5097,12 @@ ResultSet fetchResultSet();]]> When fetching data only from a single table, the type is known to jOOQ if you use jOOQ's to generate for your database tables. In order to fetch such strongly typed records, you will have to use the :

    - +System.out.println("Published in: " + book.getPublishedIn());]]>

    When you use the method, jOOQ will return the record type supplied with the argument table. Beware though, that you will no longer be able to use any clause that modifies the type of your . This includes: @@ -5223,7 +5119,7 @@ System.out.println("Published in: " + book.getPublishedIn());]]> With the introduction of generics in Java 5, it is possible in principle, to pre-define a set of tuple types. This is what Scala does. In essence, tuple types look something like this:

    - extends Tuple { T1 get1(); void set1(T1 t1); } @@ -5263,7 +5159,7 @@ for (tuple <- create val id = tuple._1; // Type is Int val title = tuple._2; // Type is String val publicationDate = tuple._3; // Type is Date -}]]> +}]]>

    It is worth mentioning that Scala is much stronger in inferring types than Java. Yet still, this becomes quickly impracticable as @@ -5276,17 +5172,17 @@ for (tuple <- create

    For these reasons jOOQ does not support generic tuples.

    -
    +
    Arrays, Maps and Lists - +

    By default, jOOQ returns an object, which is essentially a of . Often, you will find yourself wanting to transform this result object into a type that corresponds more to your specific needs. Or you just want to list all values of one specific column. Here are some examples to illustrate those use cases:

    - titles1 = create.select().from(BOOK).fetch().getValues(BOOK.TITLE); List titles2 = create.select().from(BOOK).fetch(BOOK.TITLE); String[] titles3 = create.select().from(BOOK).fetchArray(BOOK.TITLE); @@ -5306,22 +5202,22 @@ Map map4 = create.selectFrom(BOOK).fetchMap(BOOK.ID, BOOK.T Map> group1 = create.selectFrom(BOOK).fetch().intoGroups(BOOK.AUTHOR_ID); Map> group2 = create.selectFrom(BOOK).fetchGroups(BOOK.AUTHOR_ID); Map> group3 = create.selectFrom(BOOK).fetch().intoGroups(BOOK.AUTHOR_ID, BOOK.TITLE); -Map> group4 = create.selectFrom(BOOK).fetchGroups(BOOK.AUTHOR_ID, BOOK.TITLE);]]> +Map> group4 = create.selectFrom(BOOK).fetchGroups(BOOK.AUTHOR_ID, BOOK.TITLE);]]>

    Note that most of these convenience methods are available both through and , some are even available through as well.

    -
    +
    RecordHandler - +

    In a more functional operating mode, you might want to write callbacks that receive records from your select statement results in order to do some processing. This is a common data access pattern in Spring's JdbcTemplate, and it is also available in jOOQ. With jOOQ, you can implement your own classes and plug them into jOOQ's :

    - { Util.doThingsWithBook(book); }; ); -]]> -
    +]]>
    POJOs - +

    Fetching data in records is fine as long as your application is not really layered, or as long as you're still writing code in the DAO layer. But if you have a more advanced application architecture, you may not want to allow for jOOQ artefacts to leak into other layers. You may choose to write POJOs (Plain Old Java Objects) as your primary DTOs (Data Transfer Objects), without any dependencies on jOOQ's types, which may even potentially hold a reference to a , and thus a JDBC . Like Hibernate/JPA, jOOQ allows you to operate with POJOs. Unlike Hibernate/JPA, jOOQ does not "attach" those POJOs or create proxies with any magic in them.

    @@ -5360,7 +5255,7 @@ create.selectFrom(BOOK) jOOQ tries to find JPA annotations on your POJO types. If it finds any, they are used as the primary source for mapping meta-information. Only the annotation is used and understood by jOOQ. An example:

    - myBooks = create.select().from(BOOK).fetch().into(MyBook.class); -List myBooks = create.select().from(BOOK).fetchInto(MyBook.class);]]> +List myBooks = create.select().from(BOOK).fetchInto(MyBook.class);]]>

    Just as with any other JPA implementation, you can put the annotation on any class member, including attributes, setters and getters. Please refer to the Javadoc for more details. @@ -5383,7 +5278,7 @@ List myBooks = create.select().from(BOOK).fetchInto(MyBook.class);]]> - myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetch().into(MyBook2.class); -List myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchInto(MyBook2.class);]]> +List myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchInto(MyBook2.class);]]>

    Please refer to the Javadoc for more details. @@ -5419,7 +5314,7 @@ List myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchInto( jOOQ also allows for fetching data into abstract classes or interfaces, or in other words, "proxyable" types. This means that jOOQ will return a wrapped in a implementing your custom type. An example of this is given here:

    - myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetch().into(MyBook3.class); -List myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchInto(MyBook3.class);]]> +List myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchInto(MyBook3.class);]]>

    Please refer to the Javadoc for more details. @@ -5442,7 +5337,7 @@ List myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchInto( The above examples show how to fetch data into your own custom POJOs / DTOs. When you have modified the data contained in POJOs, you probably want to store those modifications back to the database. An example of this is given here:

    - +create.executeUpdate(book);]]>

    Note: Because of your manual setting of ID = 10, jOOQ's store() method will asume that you want to insert a new record. See the manual's section about for more details on this. @@ -5474,7 +5369,7 @@ create.executeUpdate(book);]]> If you're using jOOQ's , you can configure it to for you. Those DAOs operate on . An example of using such a DAO is given here:

    - +bookDao.delete(book);]]>

    More complex data structures

    jOOQ currently doesn't support more complex data structures, the way Hibernate/JPA attempt to map relational data onto POJOs. While future developments in this direction are not excluded, jOOQ claims that generic mapping strategies lead to an enormous additional complexity that only serves very few use cases. You are likely to find a solution using any of jOOQ's various , with only little boiler-plate code on the client side.

    -
    +
    Lazy fetching - +

    Unlike JDBC's , jOOQ's does not represent an open database cursor with various fetch modes and scroll modes, that needs to be closed after usage. jOOQ's results are simple in-memory Java objects, containing all of the result values. If your result sets are large, or if you have a lot of network latency, you may wish to fetch records one-by-one, or in small chunks. jOOQ supports a type for that purpose. In order to obtain such a reference, use the method. An example is given here:

    - cursor = null; try { @@ -5524,7 +5419,7 @@ finally { if (cursor != null) { cursor.close(); } -}]]> +}]]>

    As a holds an internal reference to an open , it may need to be closed at the end of iteration. If a cursor is completely scrolled through, it will conveniently close the underlying ResultSet. However, you should not rely on that. @@ -5539,16 +5434,16 @@ finally {

  • : You can use your own callbacks to receive lazily fetched records.
  • : You can fetch data into your own custom POJO types.
  • -
    +
    Many fetching - +

    Many databases support returning several result sets, or cursors, from single queries. An example for this is Sybase ASE's sp_help command:

    - sp_help 'author' + sp_help 'author' +--------+-----+-----------+-------------+-------------------+ |Name |Owner|Object_type|Object_status|Create_date | @@ -5564,14 +5459,14 @@ finally { |last_name |varchar| 50|NULL| NULL| 0| |date_of_birth|date | 4|NULL| NULL| 1| |year_of_birth|int | 4|NULL| NULL| 1| -+-------------+-------+------+----+-----+-----+]]> ++-------------+-------+------+----+-----+-----+]]>

    The correct (and verbose) way to do this with JDBC is as follows:

    - +statement.close();]]>

    As previously discussed in the chapter about , jOOQ does not rely on an internal state of any JDBC object, which is "externalised" by Javadoc. Instead, it has a straight-forward API allowing you to do the above in a one-liner:

    -> results = create.fetchMany("sp_help 'author'");]]> +> results = create.fetchMany("sp_help 'author'");]]>

    Using generics, the resulting structure is immediately clear.

    -
    +
    Later fetching - +

    Some queries take very long to execute, yet they are not crucial for the continuation of the main program. For instance, you could be generating a complicated report in a Swing application, and while this report is being calculated in your database, you want to display a background progress bar, allowing the user to pursue some other work. This can be achived simply with jOOQ, by creating a , a type that extends . An example is given here:

    - future = create.selectFrom(BOOK).where(... complex predicates ...).fetchLater(); // This example actively waits for the result to be done @@ -5624,27 +5519,25 @@ while (!future.isDone()) { } // The result should be ready, now -Result result = future.get();]]> +Result result = future.get();]]>

    Note, that instead of letting jOOQ spawn a new thread, you can also provide jOOQ with your own :

    - future = create.selectFrom(BOOK).where(... complex predicates ...).fetchLater(service);]]> - -
    +FutureResult future = create.selectFrom(BOOK).where(... complex predicates ...).fetchLater(service);]]>
    ResultSet fetching - +

    When interacting with legacy applications, you may prefer to have jOOQ return a , rather than jOOQ's own types. This can be done simply, in two ways:

    - +rs2.close();]]>

    Transform jOOQ's Result into a JDBC ResultSet

    Instead of operating on a JDBC ResultSet holding an open resource from your database, you can also let jOOQ's wrap itself in a . The advantage of this is that the so-created ResultSet has no open connection to the database. It is a completely in-memory ResultSet:

    - result = create.selectFrom(BOOK).fetch(); -ResultSet rs = result.intoResultSet();]]> +ResultSet rs = result.intoResultSet();]]>

    The inverse: Fetch data from a legacy ResultSet using jOOQ

    The inverse of the above is possible too. Maybe, a legacy part of your application produces JDBC , and you want to turn them into a :

    - result = create.fetch(rs); // As a Cursor -Cursor cursor = create.fetchLazy(rs);]]> - -
    +Cursor cursor = create.fetchLazy(rs);]]>
    Data type conversion - +

    Apart from a few extra features (see the manual's section about and ), jOOQ only supports basic types as supported by the JDBC API. In your application, you may choose to transform these data types into your own ones, without writing too much boiler-plate code. This can be done using jOOQ's types. A converter essentially allows for two-way conversion between two Java data types <T> and <U>. By convention, the <T> type corresponds to the type in your database whereas the >U> type corresponds to your own user type. The Converter API is given here:

    - extends Serializable { + extends Serializable { /** * Convert a database object to a user object @@ -5708,7 +5599,7 @@ Cursor cursor = create.fetchLazy(rs);]]> * The user type */ Class toType(); -}]]> +}]]>

    Such a converter can be used in many parts of the jOOQ API. Some examples have been illustrated in the manual's section about . @@ -5719,7 +5610,7 @@ Cursor cursor = create.fetchLazy(rs);]]> Here is a some more elaborate example involving a Converter for :

    - { @Override @@ -5748,14 +5639,14 @@ public class CalendarConverter implements Converter dates1 = create.selectFrom(BOOK).fetch().getValues(BOOK.PUBLISHING_DATE, new CalendarConverter()); List dates2 = create.selectFrom(BOOK).fetch(BOOK.PUBLISHING_DATE, new CalendarConverter()); -]]> +]]>

    Enum Converters

    jOOQ ships with a built-in default , that you can use to map VARCHAR values to enum literals or NUMBER values to enum ordinals (both modes are supported). Let's say, you want to map a YES / NO / MAYBE column to a custom Enum:

    - +}]]>

    Using Converters in generated source code

    jOOQ also allows for generated source code to reference your own custom converters, in order to permanently replace a <T> type by your own, custom <U> type. See the manual's section about for details.

    -
    +
    Static statements vs. Prepared Statements - +

    With JDBC, you have full control over your SQL statements. You can decide yourself, if you want to execute a static without bind values, or a with (or without) bind values. But you have to decide early, which way to go. And you'll have to prevent SQL injection and syntax errors manually, when inlining your bind variables.

    @@ -5795,7 +5686,7 @@ for (BookRecord book : create.selectFrom(BOOK).fetch()) { With jOOQ, this is easier. As a matter of fact, it is plain simple. With jOOQ, you can just set a flag in your , and all queries produced by that factory will be executed as static statements, with all bind values inlined. An example is given here:

    - + - - +

    Reasons for choosing one or the other

    @@ -5829,12 +5719,12 @@ inlined.select(val(1)).where(val(1).equal(1)).fetch();]]>

    Note that you don't have to inline all your bind values at once. If you know that a bind value is not really a variable and should be inlined explicitly, you can do so by using , as documented in the manual's section about

    -
    +
    Using JDBC batch operations - +

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

    @@ -5847,7 +5737,7 @@ inlined.select(val(1)).where(val(1).equal(1)).fetch();]]>

    In code, this looks like the following snippet:

    - +int[] result = stmt.executeBatch();]]>

    This will also be supported by jOOQ

    @@ -5883,7 +5773,7 @@ int[] result = stmt.executeBatch();]]> jOOQ supports executing queries in batch mode as follows:

    - -
    + .execute();]]>
    Sequence execution - +

    Most databases support sequences of some sort, to provide you with unique values to be used for primary keys and other enumerations. If you're using jOOQ's , it will generate a sequence object per sequence for you. There are two ways of using such a sequence object:

    @@ -5915,34 +5804,34 @@ create.batch(create.insertInto(AUTHOR, ID, NAME).values("?", "?")) Instead of actually phrasing a select statement, you can also use the convenience methods:

    - +BigInteger currID = create.currval(S_AUTHOR_ID);]]>

    Inlining sequence references in SQL

    You can inline sequence references in jOOQ SQL statements. The following are examples of how to do that:

    - +]]>

    For more info about inlining sequence references in SQL statements, please refer to the manual's section about .

    -
    +
    Stored procedures and functions - +

    Many RDBMS support the concept of "routines", usually calling them procedures and/or functions. These concepts have been around in programming languages for a while, also outside of databases. Famous languages distinguishing procedures from functions are:

    @@ -5991,14 +5880,14 @@ create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) If you're using jOOQ's , it will generate objects for you. Let's consider the following example:

    - +

    The generated artefacts can then be used as follows:

    - +assertEquals(new BigDecimal("2"), procedure.getId();]]>

    But you can also call the procedure using a generated convenience method in a global Routines class:

    - +assertEquals(new BigDecimal("2"), procedure.getId();]]>

    For more details about for procedures, see the manual's section about . @@ -6030,31 +5919,30 @@ assertEquals(new BigDecimal("2"), procedure.getId();]]> Unlike procedures, functions can be inlined in SQL statements to generate or , if you're using . Assume you have a function like this:

    - +

    The generated artefacts can then be used as follows:

    - + - - +

    For more info about inlining stored function references in SQL statements, please refer to the manual's section about .

    -
    +
    Oracle Packages - +

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

    @@ -6068,17 +5956,17 @@ create.select(authorExists("Paulo")).fetchOne(0, boolean.class);]]>

    For more details about for procedures and packages see the manual's section about .

    -
    +
    Oracle member procedures - +

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

    - MEMBER FUNCTION counBOOKs RETURN NUMBER ) --- The type body is omitted for the example]]> +-- The type body is omitted for the example]]>

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

    - +assertNotNull(author.getLastName());]]>

    For more details about for UDTs see the manual's section about .

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

    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 the ). You can export any Result<Record> into the formats discussed in the subsequent chapters of the manual

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

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

    - + @@ -6150,78 +6036,70 @@ String xml = create.selectFrom(BOOK).fetch().formatXML(); Animal Farm -]]> +]]>

    The same result as an can be obtained using the Result.intoXML() method:

    -// Fetch books and format them as XML -Document xml = create.selectFrom(BOOK).fetch().intoXML(); +// Fetch books and format them as XML +Document xml = create.selectFrom(BOOK).fetch().intoXML();

    See the XSD schema definition here, for a formal definition of the XML export format:
    http://www.jooq.org/xsd/jooq-export-1.6.2.xsd

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

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

    -ID,AUTHOR_ID,TITLE +ID,AUTHOR_ID,TITLE 1,1,1984 -2,1,Animal Farm +2,1,Animal Farm

    In addition to the standard behaviour, you can also specify a separator character, as well as a special string to represent NULL values (which cannot be represented in standard CSV):

    -// Use ";" as the separator character +// Use ";" as the separator character String csv = create.selectFrom(BOOK).fetch().formatCSV(';'); // Specify "{null}" as a representation for NULL values -String csv = create.selectFrom(BOOK).fetch().formatCSV(';', "{null}"); - -
    +String csv = create.selectFrom(BOOK).fetch().formatCSV(';', "{null}");
    Exporting JSON - - -// Fetch books and format them as JSON -String json = create.selectFrom(BOOK).fetch().formatJSON(); + // Fetch books and format them as JSON +String json = create.selectFrom(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"]]} -
    +{fields:["ID","AUTHOR_ID","TITLE"], + records:[[1,1,"1984"],[2,1,"Animal Farm"]]}
    Exporting HTML - -// Fetch books and format them as HTML -String html = create.selectFrom(BOOK).fetch().formatHTML(); + // Fetch books and format them as HTML +String html = create.selectFrom(BOOK).fetch().formatHTML();

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

    - + ID @@ -6241,76 +6119,72 @@ String html = create.selectFrom(BOOK).fetch().formatHTML(); Animal Farm -]]> - -
    +]]>
    Exporting Text - - -// Fetch books and format them as text -String text = create.selectFrom(BOOK).fetch().format(); + // Fetch books and format them as text +String text = create.selectFrom(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| -+---+---------+-----------+ ++---+---------+-----------+

    A simple text representation can also be obtained by calling toString() on a Result object. See also the manual's section about

    -
    +
    Importing data - +

    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 the formats described in the subsequent sections of this manual.

    -
    +
    Importing CSV - +

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

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

    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, dialect); +Factory create = new Factory(connection, dialect); // Load data into the AUTHOR table from an input stream // holding the CSV data. create.loadInto(AUTHOR) .loadCSV(inputstream) .fields(ID, AUTHOR_ID, TITLE) - .execute(); + .execute();

    Here are various other examples:

    -// Ignore the AUTHOR_ID column from the CSV file when inserting +// Ignore the AUTHOR_ID column from the CSV file when inserting create.loadInto(AUTHOR) .loadCSV(inputstream) .fields(ID, null, TITLE) @@ -6351,13 +6225,13 @@ create.loadInto(AUTHOR) .loadCSV(inputstream) .fields(ID, null, TITLE) - .execute(); + .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(); + loader = /* .. */ .execute(); // The number of processed rows int processed = loader.processed(); @@ -6380,23 +6254,21 @@ int rowIndex = error.rowIndex(); String[] row = error.row(); // The query that caused the error -Query query = error.query();]]> - -
    +Query query = error.query();]]>
    Importing XML - +

    This is not yet supported

    -
    +
    CRUD with UpdatableRecords - +

    Your database application probably consists of 50% - 80% CRUD, whereas only the remaining 20% - 50% of querying is actual querying. Most often, you will operate on records of tables without using any advanced relational concepts. This is called CRUD for

    @@ -6415,13 +6287,13 @@ Query query = error.query();]]> In normalised databases, every table has a primary key by which a tuple/record within that table can be uniquely identified. In simple cases, this is a (possibly auto-generated) number called ID. But in many cases, primary keys include several non-numeric columns. An important feature of such keys is the fact that in most databases, they are enforced using an index that allows for very fast random access to the table. A typical way to access / modify / delete a book is this:

    - +DELETE FROM BOOK WHERE ID = 5;]]>

    Normalised databases assume that a primary key is unique "forever", i.e. that a key, once inserted into a table, will never be changed or re-inserted after deletion. In order to use jOOQ's operations correctly, you should design your database accordingly. @@ -6439,24 +6311,24 @@ DELETE FROM BOOK WHERE ID = 5;]]>

    For simplicity, the term "primary key" will be used in the sense of such a "main unique key" in this manual.

    -
    +
    Simple CRUD - +

    If you're using jOOQ's , it will generate implementations for every table that has a primary key. When such a record form the database, these records are "attached" to the that created them. This means that they hold an internal reference to the same database connection that was used to fetch them. This connection is used internally by any of the following methods of the UpdatableRecord:

    - +int delete() throws DataAccessException;]]>

    See the manual's section about for some more insight on "attached" objects. @@ -6467,7 +6339,7 @@ int delete() throws DataAccessException;]]> Storing a record will perform an or an . In general, new records are always inserted, whereas records loaded from the database are always updated. This is best visualised in code:

    - +book2.store();]]>

    Some remarks about storing: @@ -6503,11 +6375,11 @@ book2.store();]]> Deleting a record will remove it from the database. Here's how you delete records:

    - +book.delete();]]>

    Refreshing

    @@ -6517,53 +6389,52 @@ book.delete();]]> In order to perform a refresh, use the following Java code:

    - +book.refresh();]]>

    CRUD and SELECT statements

    CRUD operations can be combined with regular querying, if you select records from single database tables, as explained in the manual's section about . For this, you will need to use the selectFrom() method from the :

    - -
    +}]]>
    IDENTITY values - +

    Many databases support the concept of IDENTITY values, or key values. This is reflected by JDBC's method. jOOQ abstracts using this method as many databases and JDBC drivers behave differently with respect to generated keys. Let's assume the following SQL Server BOOK table:

    - +)]]>

    If you're using jOOQ's , the above table will generate a with an IDENTITY column. This information is used by jOOQ internally, to update IDs after calling :

    - +System.out.println(book.getId());]]>

    Database compatibility

    @@ -6572,8 +6443,8 @@ System.out.println(book.getId());]]>

    These SQL dialects implement the standard very neatly.

    - +

    H2, MySQL, Postgres, SQL Server, Sybase ASE, Sybase SQL Anywhere @@ -6581,7 +6452,7 @@ id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1)]]>

    These SQL dialects implement identites, but the DDL syntax doesn’t follow the standard

    - +id INTEGER NOT NULL IDENTITY]]>

    Oracle @@ -6605,7 +6476,7 @@ id INTEGER NOT NULL IDENTITY]]>

    Oracle does not know any identity columns at all. Instead, you will have to use a trigger and update the ID column yourself, using a custom sequence. Something along these lines:

    - +END my_trigger;]]>

    Note, that this approach can be employed in most databases supporting sequences and triggers! It is a lot more flexible than standard identities

    -
    +
    Non-updatable records - +

    Tables without UNIQUE keys are considered non-updatable by jOOQ, as jOOQ has no way of uniquely identifying such a record within the database. If you're using jOOQ's , such tables will generate classes, instead of classes. When you fetch from such a table, the returned records will not allow for calling any of the methods.

    @@ -6690,12 +6559,12 @@ List books = coAuthor.fetchBookListByCoAuthorId();]]>

    Note, that some databases use internal rowid or object-id values to identify such records. jOOQ does not support these vendor-specific record meta-data.

    -
    +
    Optimistic locking - +

    jOOQ allows you to perform operations using optimistic locking. You can immediately take advantage of this feature by activating the relevant . Without any further knowledge of the underlying data semantics, this will have the following impact on store() and delete() methods:

    @@ -6710,7 +6579,7 @@ List books = coAuthor.fetchBookListByCoAuthorId();]]> The above changes to jOOQ's behaviour are transparent to the API, the only thing you need to do for it to be activated is to set the Settings flag. Here is an example illustrating optimistic locking:

    - +book2.store();]]>

    Optimised optimistic locking using TIMESTAMP fields

    If you're using jOOQ's , you can take indicate TIMESTAMP or UPDATE COUNTER fields for every generated table in the . Let's say we have this table:

    - +)]]>

    The MODIFIED column will contain a timestamp indicating the last modification timestamp for any book in the BOOK table. If you're using jOOQ and it's , jOOQ will then generate this TIMESTAMP value for you, automatically. However, instead of running an additional statement prior to an UPDATE or DELETE statement, jOOQ adds a WHERE-clause to the UPDATE or DELETE statement, checking for TIMESTAMP's integrity. This can be best illustrated with an example:

    - +book2.store();]]>

    As before, without the added TIMESTAMP column, optimistic locking is transparent to the API. @@ -6773,17 +6642,17 @@ book2.store();]]>

    Note, for explicit pessimistic locking, please consider the manual's section about the . For more details about how to configure TIMESTAMP or VERSION fields, consider the manual's section about .

    -
    +
    Batch execution - +

    When inserting, updating, deleting a lot of records, you may wish to profit from JDBC batch operations, which can be performed by jOOQ. These are available through jOOQ's as shown in the following example:

    - books = create.fetch(BOOK); // Modify the above books, and add some new ones: @@ -6791,24 +6660,24 @@ modify(books); addMore(books); // Batch-update and/or insert all of the above books -create.batchStore(books);]]> +create.batchStore(books);]]>

    Internally, jOOQ will render all the required SQL statements and execute them as a regular .

    -
    +
    DAOs - +

    If you're using jOOQ's , you can configure it to generate and DAOs for you. jOOQ then generates one DAO per , i.e. per table with a single-column primary key. Generated DAOs implement a common jOOQ type called . This type contains the following methods:

    - corresponds to the DAO's related table + corresponds to the DAO's related table //

    corresponds to the DAO's related generated POJO type // corresponds to the DAO's related table's primary key type. // Note that multi-column primary keys are not yet supported by DAOs @@ -6844,13 +6713,13 @@ public interface DAO, P, T> { // These methods provide DAO meta-information Table getTable(); Class

    getType(); -}]]> +}]]>

    Besides these base methods, generated DAO classes implement various useful fetch methods. An incomplete example is given here, for the BOOK table:

    - { // Columns with primary / unique keys produce fetchOne() methods @@ -6859,12 +6728,12 @@ public class BookDao extends DAOImpl { // Other columns produce fetch() methods, returning several records public List fetchByAuthorId(Integer... values) { ... } public List fetchByTitle(String... values) { ... } -}]]> +}]]>

    Note that you can further subtype those pre-generated DAO classes, to add more useful DAO methods to them. Using such a DAO is simple:

    - - -
    +bookDao.delete(book);]]>
    Exception handling - +

    Checked vs. unchecked exceptions

    This is an eternal and religious debate. Pros and cons have been discussed time and again, and it still is a matter of taste, today. In this case, jOOQ clearly takes a side. jOOQ's exception strategy is simple: @@ -6919,12 +6786,12 @@ bookDao.delete(book);]]>

    The following section about documents means of overriding jOOQ's exception handling, if you wish to deal separately with some types of constraint violations, or if you raise business errors from your database, etc.

    -
    +
    ExecuteListeners - +

    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, triggers, etc. Advanced ExecuteListeners can also provide custom implementations of Connection, PreparedStatement and ResultSet to jOOQ in apropriate methods.

    @@ -6935,7 +6802,7 @@ bookDao.delete(book);]]> Here is a sample implementation of an ExecuteListener, that is simply counting the number of queries per type that are being executed using jOOQ:

    - +}]]>

    Now, configure jOOQ's runtime to load your listener

    - + 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 - 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 +15:16:52,983 INFO - OTHER : 30 executions

    Please read the for more details @@ -6995,17 +6862,17 @@ for (ExecuteType type : ExecuteType.values()) {

    See also the manual's sections about and the for more sample implementations of actual ExecuteListeners.

    -
    +
    Logging - +

    jOOQ logs all SQL queries and fetched result sets to its internal DEBUG logger, which is implemented as an . By default, execute logging is activated in the . In order to see any DEBUG log output, put either log4j or slf4j on jOOQ's classpath along with their respective configuration. A sample log4j configuration can be seen here:

    - + @@ -7017,20 +6884,20 @@ for (ExecuteType type : ExecuteType.values()) { -]]> +]]>

    With the above configuration, let's fetch some data with jOOQ

    - +

    The above query may result in the following log output:

    - with bind values : select "BOOK"."ID", "BOOK"."TITLE" from "BOOK" order by "BOOK"."ID" asc, limit 2 offset 1 Query executed : Total: 1.439ms Fetched result : +----+------------+ @@ -7040,7 +6907,7 @@ Fetched result : +----+------------+ : | 3|O Alquimista| : +----+------------+ Finishing : Total: 4.814ms, +3.375ms -]]> +]]>

    Essentially, jOOQ will log @@ -7056,12 +6923,12 @@ Finishing : Total: 4.814ms, +3.375ms

    If you wish to use your own logger (e.g. avoiding printing out sensitive data), you can deactivate jOOQ's logger using and implement your own .

    -
    +
    Performance considerations - +

    Many users may have switched from higher-level abstractions such as Hibernate to jOOQ, because of Hibernate's hard-to-manage performance, when it comes to large database schemas and complex second-level caching strategies. jOOQ is not a lightweight database abstraction framework, and it comes with its own overhead. Please be sure to consider the following points:

    @@ -7076,14 +6943,14 @@ Finishing : Total: 4.814ms, +3.375ms

    Don't be put off by the above paragraphs. You should optimise wisely, i.e. only in places where you really need very high throughput to your database. jOOQ's overhead compared to plain JDBC is typically less than 1ms per query.

    -
    +
    Code generation - +

    While optional, source code generation is one of jOOQ's main assets if you wish to increase developer productivity. jOOQ's code generator takes your database schema and reverse-engineers it into a set of Java classes modelling , , , , , , user-defined types and many more.

    @@ -7097,12 +6964,12 @@ Finishing : Total: 4.814ms, +3.375ms

    The following chapters will show how to configure the code generator and how to generate various artefacts.

    -
    +
    Configuration and setup of the generator - +

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

    @@ -7129,7 +6996,7 @@ Finishing : Total: 4.814ms, +3.375ms You need to tell jOOQ some things about your database connection. Here's an example of how to do it for an Oracle database

    - + @@ -7204,7 +7071,7 @@ Finishing : Total: 4.814ms, +3.375ms [/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 for a formal specification at:
    @@ -7216,7 +7083,7 @@ Finishing : Total: 4.814ms, +3.375ms Code generation works by calling this class with the above property file as argument.

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

    Be sure that these elements are located on the classpath: @@ -7279,7 +7146,7 @@ Finishing : Total: 4.814ms, +3.375ms 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:

    - + @@ -7302,26 +7169,26 @@ Finishing : Total: 4.814ms, +3.375ms generatordatabaseinputschema="test" generatortargetpackage="org.jooq.test.generatedclasses" generatortargetdirectory="${basedir}/src"/> -]]> +]]>

    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 @@ -7373,7 +7240,7 @@ Finishing : Total: 4.814ms, +3.375ms -]]> +]]>

    See the full example of a pom.xml including the jOOQ-codegen artefact here:
    @@ -7386,7 +7253,7 @@ Finishing : Total: 4.814ms, +3.375ms 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 +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 @@ -7396,17 +7263,17 @@ Finishing : Total: 4.814ms, +3.375ms

    Be sure, both jooq-{jooq-version}.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.

    -
    +
    Advanced generator configuration - +

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

    - + @@ -7418,13 +7285,13 @@ Finishing : Total: 4.814ms, +3.375ms org.jooq.util.DefaultGeneratorStrategy -]]> +]]>

    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:

    - +}]]>

    jooq-meta configuration

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

    - + ... -]]> +]]>

    Check out the some of the manual's "advanced" sections to find out more about the advanced configuration parameters. @@ -7603,7 +7470,7 @@ public class AsInDatabaseStrategy extends DefaultGeneratorStrategy { Also, you can add some optional advanced configuration parameters for the generator:

    - + false -]]> -
    +]]>
    Generated global artefacts - +

    For increased convenience at the use-site, jOOQ generates "global" artefacts at the code generation root location, referencing tables, routines, sequences, etc. In detail, these global artefacts include the following:

    @@ -7686,7 +7552,7 @@ public class AsInDatabaseStrategy extends DefaultGeneratorStrategy { When referencing global artefacts from your client application, you would typically static import them as such:

    - -
    + .values(com.example.generated.Sequences.MY_SEQUENCE.nextval(), com.example.generated.Routines.myFunction())]]>
    Generated tables - +

    Every table in your database will generate a implementation that looks like this:

    - { + { // The singleton instance public static final Book BOOK = new Book(); @@ -7725,7 +7590,7 @@ create.insertInto(com.example.generated.Tables.MY_TABLE) } // [...] -}]]> +}]]>

    Flags influencing generated tables

    @@ -7745,17 +7610,17 @@ create.insertInto(com.example.generated.Tables.MY_TABLE)

    Table generation cannot be deactivated

    -
    +
    Generated records - +

    Every table in your database will generate a implementation that looks like this:

    - @@ -7796,7 +7661,7 @@ implements IBook { } // [...] -}]]> +}]]>

    Flags influencing generated records

    @@ -7816,17 +7681,17 @@ implements IBook {

    Record generation can be deactivated using the records flag

    -
    +
    Generated POJOs - +

    Every table in your database will generate a POJO implementation that looks like this:

    - +}]]>

    Flags influencing generated POJOs

    @@ -7879,24 +7744,24 @@ public class Book implements java.io.Serializable

    POJO generation can be activated using the pojos flag

    -
    +
    Generated Interfaces - +

    Every table in your database will generate an interface that looks like this:

    - +}]]>

    Flags influencing generated interfaces

    @@ -7911,18 +7776,18 @@ public class Book implements java.io.Serializable

    POJO generation can be activated using the interfaces flag

    -
    +
    Generated DAOs - +

    Generated DAOs

    Every table in your database will generate a implementation that looks like this:

    - { + { // Generated constructors public BookDao() { @@ -7947,43 +7812,43 @@ public class Book implements java.io.Serializable } // [...] -}]]> +}]]>

    Flags controlling DAO generation

    DAO generation can be activated using the daos flag

    -
    +
    Generated sequences - +

    Every sequence in your database will generate a implementation that looks like this:

    - S_AUTHOR_ID = new SequenceImpl("S_AUTHOR_ID", TEST, SQLDataType.INTEGER); -}]]> +}]]>

    Flags controlling sequence generation

    Sequence generation cannot be deactivated

    -
    +
    Generated procedures - +

    Every procedure or function (routine) in your database will generate a implementation that looks like this:

    - { + { // All IN, IN OUT, OUT parameters and function return values generate a static member public static final Parameter AUTHOR_NAME = createParameter("AUTHOR_NAME", SQLDataType.VARCHAR); @@ -8008,7 +7873,7 @@ public class Book implements java.io.Serializable } // [...] -}]]> +}]]>

    Package and member procedures or functions

    @@ -8019,17 +7884,17 @@ public class Book implements java.io.Serializable

    Routine generation cannot be deactivated

    -
    +
    Generated UDTs - +

    Every UDT in your database will generate a implementation that looks like this:

    - { + { // The singleton UDT instance public static final UAddressType U_ADDRESS_TYPE = new UAddressType(); @@ -8043,13 +7908,13 @@ public class Book implements java.io.Serializable createField("COUNTRY", SQLDataType.VARCHAR, U_ADDRESS_TYPE); // [...] -}]]> +}]]>

    Besides the implementation, a implementation is also generated

    - { + { // Every attribute generates a getter and a setter @@ -8061,18 +7926,18 @@ public class Book implements java.io.Serializable public String getCountry() {...} // [...] -}]]> +}]]>

    Flags controlling UDT generation

    UDT generation cannot be deactivated

    -
    +
    Master data and enumeration tables - +

    NOTE: This feature is deprecated in jOOQ 2.5.0 and will be removed as of jOOQ 3.0

    @@ -8085,7 +7950,7 @@ public class Book implements java.io.Serializable As previously discussed, you can configure master data tables as follows:

    - + @@ -8101,13 +7966,13 @@ public class Book implements java.io.Serializable [ ... ... ] - ]]> + ]]>

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

    - { + { /** * English @@ -8135,7 +8000,7 @@ public class Book implements java.io.Serializable 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. @@ -8155,39 +8020,39 @@ public class Book implements java.io.Serializable 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 BookRecord directly:

    - { + { // [...] public Language getLanguageId() { // [...] public void setLanguageId(Language 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 - +

    When using a custom type in jOOQ, you need to let jOOQ know about its associated . Ad-hoc usages of such converters has been discussed in the chapter about . 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_

    - + @@ -8210,41 +8075,39 @@ public class Book implements java.io.Serializable .*\.DATE_OF_.* -]]> +]]>

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

    - { + { // [...] public final TableField DATE_OF_BIRTH = // [...] // [...] -}]]> +}]]>

    This means that the bound type 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(AUTHOR) .where(AUTHOR.DATE_OF_BIRTH.greaterThan(new GregorianCalendar(1980, 0, 1))) - .fetch(AUTHOR.DATE_OF_BIRTH);]]> - -
    + .fetch(AUTHOR.DATE_OF_BIRTH);]]>
    Mapping generated schemata and tables - +

    We've seen previously in the chapter about , that schemata and tables can be mapped at runtime to other names. But 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 @@ -8252,25 +8115,23 @@ create.selectFrom(AUTHOR) PROD -]]> - -
    +]]>
    Tools - +

    These chapters hold some information about tools to be used with jOOQ

    -
    +
    jOOQ Console - +

    The 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:

    @@ -8310,26 +8171,26 @@ create.selectFrom(AUTHOR) 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:

    - +Factory factory = new Factory(connection, dialect, 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: @@ -8390,36 +8251,36 @@ catch (Exception ignore) {} 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 +// Create a new RemoteDebuggerServer in your application that listens to // incoming connections on a given port -SERVER = new RemoteDebuggerServer(DEBUGGER_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] +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.

    -
    +
    Reference - +

    These chapters hold some general jOOQ reference information

    -
    +
    Supported RDBMS - +

    A list of supported databases

    Every RDMBS out there has its own little specialties. jOOQ considers those specialties as much as possible, while trying to standardise the behaviour in jOOQ. In order to increase the quality of jOOQ, some 70 unit tests are run for syntax and variable binding verification, as well as some 180 integration tests with an overall of around 1200 queries for any of these databases: @@ -8478,12 +8339,12 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);

    This section will soon contain a feature matrix, documenting what feature is available for which database.

    -
    +
    Data types - +

    There is always a small mismatch between SQL data types and Java data types. This is for two reasons:

    @@ -8494,21 +8355,21 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);

    This chapter should document the most important notes about SQL, JDBC and jOOQ data types.

    -
    +
    BLOBs and CLOBs - +

    jOOQ currently doesn't explicitly support JDBC BLOB and CLOB data types. If you use any of these data types in your database, jOOQ will map them to byte[] and String instead. In simple cases (small data), this simplification is sufficient. In more sophisticated cases, you may have to bypass jOOQ, in order to deal with these data types and their respective resources. True support for LOBs is on the roadmap, though.

    -
    +
    Unsigned integer types - +

    Some databases explicitly support unsigned integer data types. In most normal JDBC-based applications, they would just be mapped to their signed counterparts letting bit-wise shifting and tweaking to the user. jOOQ ships with a set of unsigned implementations modelling the following types:

    @@ -8527,12 +8388,12 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);
  • UInteger wraps
  • ULong wraps
  • -
    +
    INTERVAL data types - +

    jOOQ fills a gap opened by JDBC, which neglects an important SQL data type as defined by the SQL standards: INTERVAL types. SQL knows two different types of intervals:

    @@ -8557,51 +8418,51 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);
  • INTERVAL * or / NUMERIC => INTERVAL
  • NUMERIC * INTERVAL => INTERVAL
  • -
    +
    XML data types - +

    XML data types are currently not supported

    -
    +
    Geospacial data types - +

    Geospacial data types

    Geospacial data types are currently not supported

    -
    +
    CURSOR data types - +

    Some databases support cursors returned from stored procedures. They are mapped to the following jOOQ data type:

    -> cursor;]]> +> cursor;]]>

    In fact, such a cursor will be fetched immediately by jOOQ and wrapped in an object.

    -
    +
    ARRAY and TABLE data types - +

    The SQL standard specifies ARRAY data types, that can be mapped to Java arrays as such:

    - intArray;]]> + intArray;]]>

    The above array type is supported by these SQL dialects: @@ -8616,23 +8477,23 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);

    Oracle has strongly-typed arrays and table types (as opposed to the previously seen anonymously typed arrays). These arrays are wrapped by types.

    -
    +
    jOOQ's BNF pseudo-notation - +

    This chapter will soon contain an overview over jOOQ's API using a pseudo BNF notation.

    -
    +
    Credits - +

    jOOQ lives in a very challenging ecosystem. The Java to SQL interface is still one of the most important system interfaces. Yet there are still a lot of open questions, best practices and no "true" standard has been established. This situation gave way to a lot of tools, APIs, utilities which essentially tackle the same problem domain as jOOQ. jOOQ has gotten great inspiration from pre-existing tools and this section should give them some credit. Here is a list of inspirational tools in alphabetical order:

    @@ -8645,7 +8506,7 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);
  • QueryDSL: A "LINQ-port" to Java. It has a similar fluent API, a similar code-generation facility, yet quite a different purpose. While jOOQ is all about SQL, QueryDSL (like LINQ) is mostly about querying.
  • Spring Data: Spring's JdbcTemplate knows RowMappers, which are reflected by jOOQ's
  • -
    +
    diff --git a/jOOQ-website/src/main/resources/manual-2.6.xml b/jOOQ-website/src/main/resources/manual-2.6.xml index 744141a3bc..28e5c5cb63 100644 --- a/jOOQ-website/src/main/resources/manual-2.6.xml +++ b/jOOQ-website/src/main/resources/manual-2.6.xml @@ -37,7 +37,7 @@
    The jOOQ User Manual. Multiple Pages - +

    # Overview

    This manual is divided into six main sections:

    @@ -88,12 +88,12 @@

    -
    +
    Preface - +

    jOOQ's reason of being - compared to JPA

    Java and SQL have come a long way. SQL is an "ancient", yet established and well-understood technology. Java is a legacy too, although its platform JVM allows for many new and contemporary languages built on top of it. Yet, after all these years, libraries dealing with the interface between SQL and Java have come and gone, leaving JPA to be a standard that is accepted only with doubts, short of any surviving options. @@ -126,18 +126,18 @@

    SQL was never meant to be abstracted. To be confined in the narrow boundaries of heavy mappers, hiding the beauty and simplicity of relational data. SQL was never meant to be object-oriented. SQL was never meant to be anything other than... SQL!

    -
    +
    Getting started with jOOQ - +

    These chapters contain a quick overview of how to get started with this manual and with jOOQ. While the subsequent chapters contain a lot of reference information, this chapter here just wraps up the essentials.

    -
    +
    How to read this manual - +

    This section helps you correctly interpret this manual in the context of jOOQ.

    @@ -279,28 +279,21 @@ and Maintenance Agreement for more details: http://www.jooq.org/eula The following are code blocks:

    - - - - - -]]> - - + +]]>

    These are useful to provide examples in code. Often, with jOOQ, it is even more useful to compare SQL code with its corresponding Java/jOOQ code. When this is done, the blocks are aligned side-by-side, with SQL usually being on the left, and Java usually being on the right:

    - + - - +

    Code block contents

    @@ -308,13 +301,11 @@ create.select()]]>

    - - - +Factory create = new Factory(connection, SQLDialect.ORACLE);]]>

    Settings

    @@ -335,16 +326,16 @@ Factory create = new Factory(connection, SQLDialect.ORACLE);]]>

    See the manual's section about to learn more about the sample database.

    -
    +
    The sample database used in this manual - +

    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 language ( +CREATE TABLE language ( id NUMBER(7) NOT NULL PRIMARY KEY, cd CHAR(2) NOT NULL, description VARCHAR2(50) @@ -382,16 +373,16 @@ CREATE TABLE book_to_book_store ( PRIMARY KEY(name, book_id), CONSTRAINT fk_b2bs_book_store FOREIGN KEY (name) REFERENCES book_store (name) ON DELETE CASCADE, CONSTRAINT fk_b2bs_book FOREIGN KEY (book_id) REFERENCES 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

    -
    +
    Different use cases for jOOQ - +

    jOOQ has originally been created as a library for complete abstraction of JDBC and all database interaction. Various best practices that are frequently encountered in pre-existing software products are applied to this library. This includes:

    @@ -420,23 +411,23 @@ CREATE TABLE book_to_book_store (

    The following sections explain about various use cases for using jOOQ in your application.

    -
    +
    jOOQ as a SQL builder - +

    This is the most simple of all use cases, allowing for construction of valid SQL for any database. In this use case, you will not use and probably not even . Instead, you'll use jOOQ to wrap strings, literals and other user-defined objects into an object-oriented, type-safe AST modelling your SQL statements. An example is given here:

    - + .getSQL();]]>

    The SQL string that you can generate as such can then be executed using JDBC directly, using Spring's JdbcTemplate, using Apache DbUtils and many other tools. @@ -448,23 +439,23 @@ String sql = create.select(fieldByName("BOOK","TITLE"), fieldByName("AUTHOR","FI

  • : This section contains a lot of information about creating SQL statements using the jOOQ API
  • : This section contains information useful in particular to those that want to supply , , etc. as plain SQL to jOOQ, rather than through generated artefacts
  • -
    +
    jOOQ as a SQL builder with code generation - +

    In addition to using jOOQ as a , you can also use jOOQ's code generation features in order to compile your SQL statements using a Java compiler against an actual database schema. This adds a lot of power and expressiveness to just simply constructing SQL using custom strings and literals, as you can be sure that all database artefacts actually exist in the database, and that their type is correct. An example is given here:

    - + .getSQL();]]>

    The SQL string that you can generate as such can then be executed using JDBC directly, using Spring's JdbcTemplate, using Apache DbUtils and many other tools. @@ -476,29 +467,29 @@ String sql = create.select(BOOK.TITLE, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)

  • : This section contains a lot of information about creating SQL statements using the jOOQ API
  • : This section contains the necessary information to run jOOQ's code generator against your developer database
  • -
    +
    jOOQ as a SQL executor - +

    Instead of any tool mentioned in the previous chapters, you can also use jOOQ directly to execute your jOOQ-generated SQL statements. This will add a lot of convenience on top of the previously discussed API for typesafe SQL construction, when you can re-use the information from generated classes to fetch records and custom data types. An example is given here:

    - result = create.select(BOOK.TITLE, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .from(BOOK) .join(AUTHOR) .on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)) .where(BOOK.PUBLISHED_IN.equal(1948)) - .fetch();]]> + .fetch();]]>

    jOOQ doesn't stop here, though! You can execute any SQL with jOOQ. In other words, you can use any other SQL building tool and run the SQL statements with jOOQ. An example is given here:

    - result = create.fetch(sql); // Or execute that SQL with JDBC, fetching the ResultSet with jOOQ: ResultSet rs = connection.createStatement().executeQuery(sql); -Result result = create.fetch(rs);]]> +Result result = create.fetch(rs);]]>

    If you wish to use jOOQ as a SQL executor with (or without) code generation, the following sections of the manual will be of interest to you: @@ -518,17 +509,17 @@ Result result = create.fetch(rs);]]>

  • : This section contains a lot of information about executing SQL statements using the jOOQ API
  • : This section contains some useful information about the various ways of fetching data with jOOQ
  • -
    +
    jOOQ for CRUD - +

    This is probably the most complete use-case for jOOQ: Use all of jOOQ's features. Apart from jOOQ's fluent API for query construction, jOOQ can also help you execute everyday CRUD operations. An example is given here:

    - +}]]>

    If you wish to use all of jOOQ's features, the following sections of the manual will be of interest to you (including all sub-sections): @@ -552,12 +543,12 @@ for (AuthorRecord author : create.fetch(AUTHOR)) {

  • : This section contains the necessary information to run jOOQ's code generator against your developer database
  • : This section contains a lot of information about executing SQL statements using the jOOQ API
  • -
    +
    jOOQ for PROs - +

    jOOQ isn't just a library that helps you and SQL against your . jOOQ ships with a lot of tools. Here are some of the most important tools shipped with jOOQ:

    @@ -571,32 +562,32 @@ for (AuthorRecord author : create.fetch(AUTHOR)) {

    If you're a power user of your favourite, feature-rich database, jOOQ will help you access all of your database's vendor-specific features, such as OLAP features, stored procedures, user-defined types, vendor-specific SQL, functions, etc. Examples are given throughout this manual.

    -
    +
    Tutorials - +

    Don't have time to read the full manual? Here are a couple of tutorials that will get you into the most essential parts of jOOQ as quick as possible.

    -
    +
    jOOQ in 7 easy steps - +

    This manual section is intended for new users, to help them get a running application with jOOQ, quickly.

    -
    +
    Step 1: Preparation - +

    If you haven't already downloaded it, download jOOQ:
    https://sourceforge.net/projects/jooq/files/Release/ @@ -605,12 +596,12 @@ for (AuthorRecord author : create.fetch(AUTHOR)) {

    Alternatively, you can create a Maven dependency:

    - + org.jooq jooq {jooq-version} -]]> +]]>

    For this example, we'll be using MySQL. If you haven't already downloaded MySQL Connector/J, download it here:
    @@ -620,17 +611,17 @@ for (AuthorRecord author : create.fetch(AUTHOR)) {

    If you don't have a MySQL instance up and running yet, get XAMPP now! XAMPP is a simple installation bundle for Apache, MySQL, PHP and Perl

    -
    +
    Step 2: Your database - +

    We're going to create a database called "guestbook" and a corresponding "posts" table. Connect to MySQL via your command line client and type the following:

    -CREATE DATABASE guestbook; +CREATE DATABASE guestbook; CREATE TABLE `posts` ( `id` bigint(20) NOT NULL, @@ -639,13 +630,12 @@ CREATE TABLE `posts` ( `title` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ); - -
    +
    Step 3: Code generation - +

    In this step, we're going to use jOOQ's command line tools to generate classes that map to the Posts table we just created. More detailed information about how to set up the jOOQ code generator can be found here:
    @@ -655,7 +645,7 @@ CREATE TABLE `posts` ( The easiest way to generate a schema is to copy the jOOQ jar files (there should be 3) and the MySQL Connector jar file to a temporary directory. Then, create a guestbook.xml that looks like this:

    - + @@ -696,7 +686,7 @@ CREATE TABLE `posts` ( C:/workspace/MySQLTest/src -]]> +]]>

    Replace the username with whatever user has the appropriate privileges to query the database meta data. You'll also want to look at the other values and replace as necessary. Here are the two interesting properties:

    @@ -711,15 +701,15 @@ CREATE TABLE `posts` ( Once you have the JAR files and guestbook.xml in your temp directory, type this (use colons instead of semi-colons on UNIX/Linux systems):

    -java -classpath jooq-{jooq-version}.jar;jooq-meta-{jooq-version}.jar;jooq-codegen-{jooq-version}.jar;mysql-connector-java-5.1.18-bin.jar;. +java -classpath jooq-{jooq-version}.jar;jooq-meta-{jooq-version}.jar;jooq-codegen-{jooq-version}.jar;mysql-connector-java-5.1.18-bin.jar;. org.jooq.util.GenerationTool /guestbook.xml - +

    Note the prefix slash before guestbook.xml. Even though it's in our working directory, we need to prepend a slash, as the configuration file is loaded from the classpath. Replace the filenames with your filenames. In this example, jOOQ {jooq-version} is being used. If everything has worked, you should see this in your console output:

    -Nov 1, 2011 7:25:06 PM org.jooq.impl.JooqLogger info +Nov 1, 2011 7:25:06 PM org.jooq.impl.JooqLogger info INFO: Initialising properties : /guestbook.xml Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info INFO: Database parameters @@ -777,19 +767,17 @@ Nov 1, 2011 7:25:08 PM org.jooq.impl.JooqLogger info INFO: Packages fetched : 0 (0 included, 0 excluded) Nov 1, 2011 7:25:08 PM org.jooq.impl.JooqLogger info INFO: GENERATION FINISHED! : Total: 791.688ms, +9.143ms - - -
    +
    Step 4: Connect to your database - +

    Let's just write a vanilla main class in the project containing the generated classes:

    - +}]]>

    This is pretty standard code for establishing a MySQL connection.

    -
    +
    Step 5: Querying - +

    Let's add a simple query:

    - result = create.select().from(POSTS).fetch();]]> + result = create.select().from(POSTS).fetch();]]>

    First get an instance of Factory so we can write a simple SELECT query. We pass an instance of the MySQL connection to Factory. Note that the factory doesn't close the connection. We'll have to do that ourselves. @@ -840,29 +828,29 @@ Result result = create.select().from(POSTS).fetch();]]>

    We then use jOOQ's DSL to return an instance of Result. We'll be using this result in the next step.

    -
    +
    Step 6: Iterating - +

    After the line where we retrieve the results, let's iterate over the results and print out the data:

    - +}]]>

    The full program should now look like this:

    - -
    +}]]>
    Step 7: Explore! - +

    jOOQ has grown to be a comprehensive SQL library. For more information, please consider the manual:
    http://www.jooq.org/manual/ @@ -941,37 +928,37 @@ public class Main { This tutorial is the courtesy of Ikai Lan. See the original source here:
    http://ikaisays.com/2011/11/01/getting-started-with-jooq-a-tutorial/

    -
    +
    Using jOOQ in modern IDEs - +

    Feel free to contribute a tutorial!

    -
    +
    Using jOOQ with Spring - +

    Feel free to contribute a tutorial!

    -
    +
    A simple web application with jOOQ - +

    Feel free to contribute a tutorial!

    -
    +
    jOOQ and Scala - +

    As any other library, jOOQ can be easily used in Scala, taking advantage of the many Scala language features such as for example:

    @@ -994,7 +981,7 @@ public class Main { A short example jOOQ application in Scala might look like this:

    - +}]]>

    For more details about jOOQ's Scala integration, please refer to the manual's section about .

    -
    +
    Dependencies - +

    jOOQ has no dependencies on any third-party libraries. This rule has some exceptions:

    @@ -1057,14 +1044,14 @@ object Test { //

    In order to build jOOQ, please download the sources from https://github.com/jOOQ/jOOQ and use Maven to build it, preferably in Eclipse.

    -
    +
    SQL building - +

    SQL is a declarative language that is hard to integrate into procedural, object-oriented, functional or any other type of programming languages. jOOQ's philosophy is to give SQL the credit it deserves and integrate SQL itself as an "internal domain specific language" directly into Java.

    @@ -1074,12 +1061,12 @@ object Test { //

    This section explains all about the various syntax elements involved with jOOQ's SQL building capabilities. For a complete overview of all syntax elements, please refer to the manual's section about

    -
    +
    The Factory class - +

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

    @@ -1100,13 +1087,13 @@ object Test { //

    With jOOQ 2.0, static factory methods have been introduced in order to make client 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.*; + import static org.jooq.impl.Factory.*;

    Note, that when working with Eclipse, you could also add the Factory to your favourites. This will allow to access functions even more fluently:

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

    The Factory as a Configuration object

    @@ -1121,20 +1108,19 @@ Factory.concat(Factory.trim(FIRST_NAME), Factory.trim(LAST_NAME));

    As a Configuration object, a Factory can construct , for later . An example is given here:

    - select = create.selectOne(); // Using the internally referenced Factory, the select statement can now be executed: -Result result = select.fetch();]]> -
    +Result result = select.fetch();]]>
    SQL Dialect - +

    While jOOQ tries to represent the SQL standard as much as possible, many features are vendor-specific to a given database and to its "SQL dialect". jOOQ models this using the enum type.

    @@ -1144,26 +1130,26 @@ Result result = select.fetch();]]>

    Some parts of the jOOQ API are officially supported only by a given subset of the supported SQL dialects. For instance, the , which is supported by the Oracle and CUBRID databases, is annotated with a annotation, as such:

    -CONNECT BY clause to the query */ @Support({ CUBRID, ORACLE }) -SelectConnectByConditionStep connectBy(Condition condition);]]> +SelectConnectByConditionStep connectBy(Condition condition);]]>

    jOOQ API methods which are not annotated with the annotation, or which are annotated with the Support annotation, but without any SQL dialects can be safely used in all SQL dialects. An example for this is the factory method:

    -... fields);]]> +SelectSelectStep select(Field... fields);]]>

    jOOQ's SQL clause simulation capabilities

    The aforementioned Support annotation does not only designate, which databases natively support a feature. It also indicates that a feature is simulated by jOOQ for some databases lacking this feature. An example of this is the , a predicate syntax defined by SQL:1999 and implemented only by H2, HSQLDB, and Postgres:

    - +

    Nevertheless, the IS DISTINCT FROM predicate is supported in all dialects, as its semantics can be expressed with an equivalent . For more details, see the manual's section about the . @@ -1183,12 +1169,12 @@ SelectSelectStep select(Field... fields);]]>

    jOOQ has a historic affinity to Oracle's SQL extensions. If something is supported in Oracle SQL, it has a high probability of making it into the jOOQ API

    -
    +
    Connection vs. DataSource - +

    Interact with JDBC Connections

    While you can use jOOQ for only, you can also run queries against a JDBC . Internally, jOOQ creates or objects from such a Connection, in order to execute statements. The normal operation mode is to provide a with a JDBC Connection, whose lifecycle you will control yourself. This means that jOOQ will not actively close connections, rollback or commit transactions. @@ -1197,12 +1183,12 @@ SelectSelectStep select(Field... fields);]]>

    If you're in a J2EE or Spring context, however, you may wish to use a instead. Currently, Connections obtained from such a DataSource will be closed after query execution by jOOQ. The semantics of such a close operation should be the returning of the connection into a connection pool, not the actual closing of the underlying physical connection. Typically, this makes sense in an environment using distributed JTA transactions. An example of using DataSources with jOOQ can be seen in the tutorial section about .

    -
    +
    Custom 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:

    @@ -1216,9 +1202,9 @@ SelectSelectStep select(Field... fields);]]>

    For example, if you want to indicate to jOOQ, that it should inline all bind variables, and execute static instead of binding its variables to , you can do so by using the following Factory:

    - +Factory create = new Factory(connection, dialect, settings);]]>

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

    @@ -1240,12 +1226,12 @@ Factory create = new Factory(connection, dialect, settings);]]> Please refer to the jOOQ runtime configuration XSD for more details:
    http://www.jooq.org/xsd/jooq-runtime-2.5.0.xsd

    -
    +
    Runtime schema and table mapping - +

    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. @@ -1265,7 +1251,7 @@ Factory create = new Factory(connection, dialect, settings);]]> 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 with. Take the following example:

    -Settings settings = new Settings() +Settings settings = new Settings() .withRenderMapping(new RenderMapping() .withSchemata( new MappedSchema().withInput("DEV") @@ -1275,13 +1261,13 @@ Factory create = new Factory(connection, dialect, settings);]]> Factory create = new Factory(connection, SQLDialect.ORACLE, settings); // Run queries with the "mapped" factory -create.selectFrom(AUTHOR).fetch(); +create.selectFrom(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.AUTHOR +SELECT * FROM MY_BOOK_WORLD.AUTHOR

    Even if AUTHOR was generated from DEV.

    @@ -1291,7 +1277,7 @@ create.selectFrom(AUTHOR).fetch(); 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):

    - + @@ -1304,13 +1290,13 @@ create.selectFrom(AUTHOR).fetch(); -]]> +]]>

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

    -Settings settings = JAXB.unmarshal(new File("jooq-runtime.xml"), Settings.class); +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 @@ -1322,40 +1308,40 @@ create.selectFrom(AUTHOR).fetch(); 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 +// Set the default schema Schema MY_BOOK_WORLD = ... create.use(MY_BOOK_WORLD); // Run queries with factory having a default schema -create.selectFrom(AUTHOR).fetch(); +create.selectFrom(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 AUTHOR +-- the schema name is omitted from all SQL constructs. +SELECT * FROM AUTHOR

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

    -Settings settings = new Settings() +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(AUTHOR).fetch(); +create.selectFrom(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.AUTHOR to something MY_BOOK_WORLD.MY_APP__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() +Settings settings = new Settings() .withRenderMapping(new RenderMapping() .withSchemata( new MappedSchema().withInput("DEV") @@ -1368,13 +1354,13 @@ create.selectFrom(AUTHOR).fetch(); Factory create = new Factory(connection, SQLDialect.ORACLE, settings); // Run queries with the "mapped" factory -create.selectFrom(AUTHOR).fetch(); +create.selectFrom(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__AUTHOR +SELECT * FROM MY_BOOK_WORLD.MY_APP__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! @@ -1384,20 +1370,20 @@ create.selectFrom(AUTHOR).fetch();

    Note that the manual's section about explains how you can hard-wire your schema mappings at code generation time

    -
    +
    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 +// A general, dialect-unspecific factory Factory create = new Factory(connection, SQLDialect.MYSQL); // A MySQL-specific factory -MySQLFactory create = new MySQLFactory(connection); +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:

    @@ -1408,23 +1394,23 @@ MySQLFactory create = new MySQLFactory(connection);

    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. By default, such a schema-specific Factory will not render the schema name.

    -
    +
    SQL Statements - +

    jOOQ currently supports 6 types of SQL statements. All of these statements are constructed from a Factory instance with an optional . If supplied with a Connection or DataSource, they can be executed. Depending on the , executed queries can return results.

    -
    +
    jOOQ's DSL and non-DSL API - +

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

    @@ -1432,22 +1418,21 @@ MySQLFactory create = new MySQLFactory(connection); Here is an example to illustrate what that means:

    - 1920 AND a.first_name = 'Paulo' - ORDER BY b.title]]> - result = + ORDER BY b.title]]> result = create.select() .from(AUTHOR.as("a")) .join(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();]]> + .fetch();]]>

    We'll see how the aliasing works later in the section about @@ -1457,16 +1442,16 @@ create.select()

    Many other frameworks have similar APIs with similar feature sets. Yet, what makes jOOQ special is its informal modelling a unified SQL dialect suitable for many vendor-specific dialects, and implementing that BNF notation as a hierarchy of interfaces in Java. This concept is extremely powerful, when with syntax completion. Not only can you code much faster, your SQL code will be compile-checked to a certain extent. An example of a DSL query equivalent to the previous one is given here:

    - result = create.select() .from(AUTHOR) .join(BOOK).on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)) - .fetch();]]> + .fetch();]]>

    Unlike other, simpler frameworks that use "fluent APIs" or "method chaining", jOOQ's BNF-based interface hierarchy will not allow bad query syntax. The following will not compile, for instance:

    - result = create.select() .join(BOOK).on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)) // ^^^^ "join" is not possible here @@ -1482,13 +1467,13 @@ Result result = create.select() Result result = create.select(rowNumber()) // ^^^^^^^^^ "over()" is missing here .from(AUTHOR) - .fetch();]]> + .fetch();]]>

    History of SQL building and incremental query building (a.k.a. the non-DSL API)

    Historically, jOOQ started out as an object-oriented SQL builder library like any other. This meant that all queries and their syntactic components were modeled as so-called , which delegate and to child components. This part of the API will be referred to as the non-DSL API, which is still maintained and used internally by jOOQ for incremental query building. An example of incremental query building is given here:

    - result = query.fetch();]]> +Result result = query.fetch();]]>

    This query is equivalent to the one shown before using the DSL syntax. In fact, internally, the DSL API constructs precisely this QueryObject. Note, that you can always access the SelectQuery object to switch between DSL and non-DSL APIs:

    - +query.addJoin(BOOK, BOOK.AUTHOR_ID.equal(AUTHOR.ID));]]>

    Mutability

    Note, that for historic reasons, the DSL API mixes mutable and immutable behaviour with respect to the internal representation of the being constructed. While creating , (such as functions) assumes immutable behaviour, creating does not. In other words, the following can be said:

    - +s2 == s3; // The internal object is always the same]]>

    Mutability may be removed in a future version of jOOQ.

    -
    +
    The SELECT statement - +

    When you don't just perform (i.e. SELECT * FROM your_table WHERE ID = ?), you're usually generating new record 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:

    - + - - +

    Details about the various clauses of this query will be provided in subsequent sections @@ -1594,14 +1578,14 @@ create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, count()) A very similar, but limited API is available, if you want to select from single physical tables in order to retrieve . 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:

    - SimpleSelectWhereStep selectFrom(Table table);]]> + SimpleSelectWhereStep selectFrom(Table 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:

    - + .fetchAny();]]>

    The simple SELECT API is limited in the way that it does not support any of these clauses: @@ -1615,41 +1599,39 @@ create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, count())

    In most parts of this manual, it is assumed that you do not use the simple SELECT API. For more information about the simple SELECT API, see the manual's section about .

    -
    +
    The SELECT clause - +

    The SELECT clause lets you project your own record types, referencing table fields, functions, arithmetic expressions, etc. The Factory provides several methods for expressing a SELECT clause:

    - + - s1 = create.select(BOOK.ID, BOOK.TITLE); Select s2 = create.select(BOOK.ID, trim(BOOK.TITLE));]]> - +

    Some commonly used projections can be easily created using convenience methods:

    - + - select1 = create.selectCount(); Select select2 = create.selectZero(); Select select2 = create.selectOne();]]> - +

    See more details about functions and expressions in the manual's section about @@ -1660,28 +1642,26 @@ Select select2 = create.selectOne();]]> The DISTINCT keyword can be included in the method name, constructing a SELECT clause

    - - - select1 = create.selectDistinct(BOOK.TITLE);]]> - -
    + + select1 = create.selectDistinct(BOOK.TITLE);]]> + +
    The FROM clause - +

    The SQL FROM clause allows for specifying any number of to select data from. The following are examples of how to form normal FROM clauses:

    - + - - +

    Read more about aliasing in the manual's section about . @@ -1692,12 +1672,11 @@ create.selectOne().from(BOOK.as("b"), AUTHOR.as("a"));]]> Apart from simple tables, you can pass any arbitrary to the jOOQ FROM clause. This may include in Oracle:

    - + - - +

    Note, in order to access the DbmsXplan package, you can use the to generate Oracle's SYS schema. @@ -1709,22 +1688,21 @@ FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(null, null, 'ALLSTATS'));]]> In many SQL dialects, FROM is a mandatory clause, in some it isn't. jOOQ allows you to omit the FROM clause, returning just one record. An example:

    - + - - +

    Read more about dual or dummy tables in the manual's section about . The following are examples of how to form normal FROM clauses:

    -
    +
    The JOIN clause - +

    jOOQ supports many different types of standard SQL JOIN operations:

    @@ -1743,7 +1721,7 @@ new Factory(SQLDialect.POSTGRES).selectOne().getSQL();]]> All of these JOIN methods can be called on types, or directly after the FROM clause for convenience. The following example joins AUTHOR and BOOK

    - result = create.select() @@ -1756,27 +1734,26 @@ Result result = create.select() .from(AUTHOR) .join(BOOK) .on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)) - .fetch();]]> + .fetch();]]>

    The two syntaxes will produce the same SQL statement. However, calling "join" on objects allows for more powerful, nested JOIN expressions (if you can handle the parentheses):

    - + - + .on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)));]]>
    • See the section about to learn more about the many ways to create objects in jOOQ.
    • @@ -1788,13 +1765,12 @@ create.select() Surprisingly, SQL does not allow to formally JOIN on well-known foreign key relationship information. Naturally, when you join BOOK to AUTHOR, you will want to do that based on the BOOK.AUTHOR_ID foreign key to AUTHOR.ID primary key relation. Not being able to do this in SQL leads to a lot of repetitive code, re-writing the same JOIN predicate again and again - especially, when your foreign keys contain more than one column. With jOOQ, when you use , you can use foreign key constraint information in JOIN expressions as such:

      - + - + .join(BOOK).onKey();]]>

      In case of ambiguity, you can also supply field references for your foreign keys, or the generated foreign key reference to the onKey() method. @@ -1805,137 +1781,130 @@ JOIN BOOK ON BOOK.AUTHOR_ID = AUTHOR.ID]]> Most often, you will provide jOOQ with JOIN conditions in the JOIN .. ON clause. SQL supports a different means of specifying how two tables are to be joined. This is the JOIN .. USING clause. Instead of a condition, you supply a set of fields whose names are common to both tables to the left and right of a JOIN operation. This can be useful when your database schema has a high degree of relational normalisation. An example:

      - + - + .join(BOOK).using(AUTHOR.AUTHOR_ID);]]>

      In schemas with high degrees of normalisation, you may also choose to use NATURAL JOIN, which takes no JOIN arguments as it joins using all fields that are common to the table expressions to the left and to the right of the JOIN operator. An example:

      - + - + .naturalJoin(BOOK);]]>

      Oracle's partitioned OUTER JOIN

      Oracle SQL ships with a special syntax available for OUTER JOIN clauses. According to the Oracle documentation about partitioned outer joins this can be used to fill gaps for simplified analytical calculations. jOOQ only supports putting the PARTITION BY clause to the right of the OUTER JOIN clause. The following example will create at least one record per AUTHOR and per existing value in BOOK.PUBLISHED_IN, regardless if an AUTHOR has actually published a book in that year.

      - + - + .on(BOOK.AUTHOR_ID.equal(AUTHOR.ID));]]> - +
    The WHERE clause - +

    The WHERE clause can be used for JOIN or filter predicates, in order to restrict the data returned by the supplied to the previously specified and . Here is an example:

    - + - + .and(BOOK.TITLE.equal("1984"));]]>

    The above syntax is convenience provided by jOOQ, allowing you to connect the supplied in the WHERE clause with another condition using an AND operator. You can of course also create a more complex condition and supply that to the WHERE clause directly (observe the different placing of parentheses). The results will be the same:

    - + - + BOOK.TITLE.equal("1984")));]]>

    You will find more information about creating later in the manual.

    -
    +
    The CONNECT BY clause - +

    The Oracle database knows a very succinct syntax for creating hierarchical queries: the CONNECT BY clause, which is fully supported by jOOQ, including all related functions and pseudo-columns. A more or less formal definition of this clause is given here:

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

    An example for an iterative query, iterating through values between 1 and 5 is this:

    - + - + .connectBy(level().lessOrEqual(5));]]>

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

    - + - - +

    The output might then look like this

    -+------------------------------------------------+ ++------------------------------------------------+ |substring | +------------------------------------------------+ |C: | @@ -1945,7 +1914,7 @@ ORDER BY 1]]> |C:/eclipse/eclipse.exe | +------------------------------------------------+ |...21 record(s) truncated... - +

    Some of the supported functions and pseudo-columns are these (available from the ): @@ -1969,38 +1938,36 @@ ORDER BY 1]]> The Oracle database allows for specifying a SIBLINGS keyword in the . Instead of ordering the overall result, this will only order siblings among each other, keeping the hierarchy intact. An example is given here:

    - + - - + -
    +
    The GROUP BY clause - +

    GROUP BY can be used to create unique groups of data, to form aggregations, to remove duplicates and for other reasons. It will transform your previously defined , and return only one record per unique group as specified in this clause. For instance, you can group books by BOOK.AUTHOR_ID:

    - + - + .groupBy(AUTHOR_ID);]]>

    As defined in the SQL standard, when grouping, you may no longer project any columns that are not a formal part of the GROUP BY clause, or . The above example counts all books per author @@ -2011,13 +1978,12 @@ GROUP BY AUTHOR_ID]]> MySQL has a peculiar way of not adhering to this standard behaviour. This is documented in the MySQL manual. In short, with MySQL, you can also project any other field that are not part of the GROUP BY clause. The projected values will just be arbitrary values from within the group. You cannot rely on any ordering. For example:

    - + - + .groupBy(AUTHOR_ID);]]>

    This will return an arbitrary title per author. jOOQ supports this syntax, as jOOQ is not doing any checks internally, about the consistence of tables/fields/functions that you provide it. @@ -2028,68 +1994,64 @@ GROUP BY AUTHOR_ID]]> jOOQ supports empty GROUP BY () clauses as well. This will result in that return only one record.

    - + - + .groupBy();]]>

    ROLLUP(), CUBE() and GROUPING SETS()

    Some databases support the SQL standard grouping functions and some extensions thereof. See the manual's section about for more details.

    -
    +
    The HAVING clause - +

    The HAVING clause is commonly used to further restrict data resulting from a previously issued . An example, selecting only those authors that have written at least two books:

    - + = 2]]> -= 2]]> + .having(count().greaterOrEqual(2));]]>

    According to the SQL standard, you may omit the GROUP BY clause and still issue a HAVING clause. This will implicitly GROUP BY (). jOOQ also supports this syntax. The following example selects one record, only if there are at least 4 books in the books table:

    - + = 4]]> -= 4]]> + .having(count().greaterOrEqual(4));]]> -
    +
    The ORDER BY clause - +

    Databases are allowed to return data in any arbitrary order, unless you explicitly declare that order in the ORDER BY clause. In jOOQ, this is straight-forward:

    - + - + .orderBy(BOOK.AUTHOR_ID.asc(), BOOK.TITLE.desc());]]>

    Any jOOQ can be transformed into an by calling the asc() and desc() methods. @@ -2100,13 +2062,12 @@ ORDER BY AUTHOR_ID ASC, TITLE DESC]]> The SQL standard allows for specifying integer literals (, not !) to reference column indexes from the projection (). This may be useful if you do not want to repeat a lengthy expression, by which you want to order - although most databases also allow for referencing in the ORDER BY clause. An example of this is given here:

    - + - + .orderBy(one().asc(), inline(2).desc());]]>

    Note, how one() is used as a convenience short-cut for inline(1) @@ -2117,87 +2078,84 @@ ORDER BY 1 ASC, 2 DESC]]> A few databases support the SQL standard "null ordering" clause in sort specification lists, to define whether NULL values should come first or last in an ordered result.

    - + - + BOOK.CO_AUTHOR_ID.asc().nullsLast());]]>

    If your database doesn't support this syntax, jOOQ simulates it using a as follows

    - + - + BOOK.CO_AUTHOR_ID.asc().nullsLast());]]>

    Ordering using CASE expressions

    Using in SQL ORDER BY clauses is a common pattern, if you want to introduce some sort indirection / sort mapping into your queries. As with SQL, you can add any type of into your ORDER BY clause. For instance, if you have two favourite books that you always want to appear on top, you could write:

    - + - + .otherwise(2).asc());]]>

    But writing these things can become quite verbose. jOOQ supports a convenient syntax for specifying sort mappings. The same query can be written in jOOQ as such:

    - + .orderBy(BOOK.TITLE.sortAsc("1984", "Animal Farm"));]]>

    More complex sort indirections can be provided using a Map:

    -() {{ put("1984", 1); put("Animal Farm", 13); put("The jOOQ book", 10); - }}));]]> + }}));]]>

    Of course, you can combine this feature with the previously discussed NULLS FIRST / NULLS LAST feature. So, if in fact these two books are the ones you like least, you can put all NULLS FIRST (all the other books):

    - + .orderBy(BOOK.TITLE.sortAsc("1984", "Animal Farm").nullsFirst());]]>

    jOOQ's understanding of SELECT .. ORDER BY

    @@ -2209,23 +2167,23 @@ ORDER BY CASE TITLE

    jOOQ also supports Oracle's SIBLINGS keyword to be used with ORDER BY clauses for

    -
    +
    The LIMIT .. OFFSET clause - +

    While being extremely useful for every application that does paging, or just to limit result sets to reasonable sizes, this clause is not yet part of any SQL standard (up until SQL:2008). Hence, there exist a variety of possible implementations in various SQL dialects, concerning this limit clause. jOOQ chose to implement the LIMIT .. OFFSET clause as understood and supported by MySQL, H2, HSQLDB, Postgres, and SQLite. Here is an example of how to apply limits with jOOQ:

    - +

    This will limit the result to 1 books starting with the 2nd book (starting at offset 0!). limit() is supported in all dialects, offset() in all but Sybase ASE, which has no reasonable means to simulate it. This is how jOOQ simulates the above query in various SQL dialects:

    - 1 AND ROWNUM_98843777 <= 3 -]]> +]]>

    As you can see, jOOQ will take care of the incredibly painful ROW_NUMBER() OVER() (or ROWNUM for Oracle) filtering in subselects for you, you'll just have to write limit(1).offset(2) in any dialect. @@ -2270,39 +2228,37 @@ AND ROWNUM_98843777 <= 3

    As can be seen in the above example, writing correct SQL can be quite tricky, depending on the SQL dialect. For instance, with SQL Server, you cannot have an ORDER BY clause in a subquery, unless you also have a TOP clause. This is illustrated by the fact that jOOQ renders a TOP 100 PERCENT clause for you. The same applies to the fact that ROW_NUMBER() OVER() needs an ORDER BY windowing clause, even if you don't provide one to the jOOQ query. By default, jOOQ adds ordering by the first column of your projection.

    -
    +
    The FOR UPDATE clause - +

    For inter-process synchronisation and other reasons, you may choose to use the SELECT .. FOR UPDATE clause to indicate to the database, that a set of cells or records should be locked by a given transaction for subsequent updates. With jOOQ, this can be achieved as such:

    - + - + .forUpdate();]]>

    The above example will produce a record-lock, locking the whole record for updates. Some databases also support cell-locks using FOR UPDATE OF ..

    - + - + .forUpdate().of(BOOK.TITLE);]]>

    Oracle goes a bit further and also allows to specify the actual locking behaviour. It features these additional clauses, which are all supported by jOOQ: @@ -2316,15 +2272,15 @@ FOR UPDATE OF TITLE]]> With jOOQ, you can use those Oracle extensions as such:

    - +create.select().from(BOOK).where(BOOK.ID.equal(3)).forUpdate().skipLocked();]]>

    FOR UPDATE in CUBRID and SQL Server

    The SQL standard specifies a FOR UPDATE clause to be applicable for cursors. Most databases interpret this as being applicable for all SELECT statements. An exception to this rule are the CUBRID and SQL Server databases, that do not allow for any FOR UPDATE clause in a regular SQL SELECT statement. jOOQ simulates the FOR UPDATE behaviour, by locking record by record with JDBC. JDBC allows for specifying the flags TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE for any statement, and then using ResultSet.updateXXX() methods to produce a cell-lock / row-lock. Here's a simplified example in JDBC:

    - +}]]>

    The main drawback of this approach is the fact that the database has to maintain a scrollable cursor, whose records are locked one by one. This can cause a major risk of deadlocks or race conditions if the JDBC driver can recover from the unsuccessful locking, if two Java threads execute the following statements:

    - +SELECT * FROM author ORDER BY id DESC;]]>

    So use this technique with care, possibly only ever locking single rows! @@ -2361,12 +2317,12 @@ SELECT * FROM author ORDER BY id DESC;]]>

    Note, that jOOQ also supports optimistic locking, if you're doing simple CRUD. This is documented in the section's manual about .

    -
    +
    UNION, INTERSECTION and EXCEPT - +

    SQL allows to perform set operations as understood in standard set theory on result sets. These operations include unions, intersections, subtractions. For two subselects to be combinable by such a set operator, each subselect must return a of the same arity and type.

    @@ -2376,13 +2332,12 @@ SELECT * FROM author ORDER BY id DESC;]]> These operators combine two results into one. While UNION removes all duplicate records resulting from this combination, UNION ALL leaves subselect results as they are. Typically, you should prefer UNION ALL over UNION, if you don't really need to remove duplicates. The following example shows how to use such a UNION operation in jOOQ.

    - + - +create.selectFrom(BOOK).where(BOOK.ID.equal(5)));]]>

    INTERSECT [ ALL ] and EXCEPT [ ALL ]

    @@ -2394,76 +2349,73 @@ create.selectFrom(BOOK).where(BOOK.ID.equal(5)));]]> As previously mentioned in the manual's section about the , jOOQ has slightly changed the semantics of these set operators. While in SQL, a subselect may not contain any or (unless you wrap the subselect into a ), jOOQ allows you to do so. In order to select both the youngest and the oldest author from the database, you can issue the following statement with jOOQ (rendered to the MySQL dialect):

    - + - + .orderBy(AUTHOR.DATE_OF_BIRTH.desc()).limit(1));]]> -
    +
    Oracle-style hints - +

    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 AUTHOR +SELECT /*+ALL_ROWS*/ FIRST_NAME, LAST_NAME + FROM AUTHOR

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

    -create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) +create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .hint("/*+ALL_ROWS*/") - .from(AUTHOR); + .from(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

    -
    +
    The INSERT statement - +

    The INSERT statement is used to insert new records into a database table. Records can either be supplied using a VALUES() constructor, or a SELECT statement. jOOQ supports both types of INSERT statements. An example of an INSERT statement using a VALUES() constructor is given here:

    - + INSERT INTO AUTHOR (ID, FIRST_NAME, LAST_NAME) -VALUES (100, 'Hermann', 'Hesse'); -create.insertInto(AUTHOR, +VALUES (100, 'Hermann', 'Hesse');create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) - .values(100, "Hermann", "Hesse"); + .values(100, "Hermann", "Hesse");

    INSERT multiple rows with the VALUES() constructor

    The SQL standard specifies that multiple rows can be supplied to the VALUES() constructor in an INSERT statement. Here's an example of a multi-record INSERT

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

    jOOQ tries to stay close to actual SQL. In detail, however, Java's expressiveness is limited. That's why the values() clause is repeated for every record in multi-record inserts. @@ -2472,30 +2424,29 @@ VALUES (100, 'Hermann', 'Hesse'), Some RDBMS do not support inserting several records in a single statement. In those cases, jOOQ simulates multi-record INSERTs using the following SQL:

    - + INSERT INTO AUTHOR (ID, FIRST_NAME, LAST_NAME) SELECT 100, 'Hermann', 'Hesse' FROM DUAL UNION ALL -SELECT 101, 'Alfred', 'Döblin' FROM DUAL; -create.insertInto(AUTHOR, +SELECT 101, 'Alfred', 'Döblin' FROM DUAL;create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .values(100, "Hermann", "Hesse") .values(101, "Alfred", "Döblin"); - +

    INSERT using jOOQ's alternative syntax

    MySQL (and some other RDBMS) allow for using a non-SQL-standard, 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(AUTHOR) +create.insertInto(AUTHOR) .set(AUTHOR.ID, 100) .set(AUTHOR.FIRST_NAME, "Hermann") .set(AUTHOR.LAST_NAME, "Hesse") .newRecord() .set(AUTHOR.ID, 101) .set(AUTHOR.FIRST_NAME, "Alfred") - .set(AUTHOR.LAST_NAME, "Döblin"); + .set(AUTHOR.LAST_NAME, "Döblin");

    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. Internally, the two syntaxes are strictly equivalent. @@ -2506,12 +2457,12 @@ SELECT 101, 'Alfred', 'Döblin' FROM DUAL; 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 (i.e. if they support the SQL standard ). Here is an example how to use the ON DUPLICATE KEY UPDATE clause:

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

    The synthetic ON DUPLICATE KEY IGNORE clause

    @@ -2519,18 +2470,18 @@ create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.LAST_NAME) 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 :

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

    Postgres's INSERT .. RETURNING

    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:

    - record = create.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .values("Charlotte", "Roche") @@ -2547,7 +2498,7 @@ create.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .values("Friedrich", "Schiller") // You can request any field. Also trigger-generated values .returning(AUTHOR.ID, AUTHOR.CREATION_DATE) - .fetch();]]> + .fetch();]]>

    Some databases have poor support for returning generated keys after INSERTs. In those cases, jOOQ might need to issue another in order to fetch an @@identity value. Be aware, that this can lead to race-conditions in those databases that cannot properly return generated ID values. For more information, please consider the jOOQ Javadoc for the returning() clause. @@ -2559,53 +2510,49 @@ create.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) In some occasions, you may prefer the INSERT SELECT syntax, for instance, when you copy records from one table to another:

    -create.insertInto(AUTHOR_ARCHIVE) - .select(create.selectFrom(AUTHOR).where(AUTHOR.DECEASED.isTrue())); - -
    +create.insertInto(AUTHOR_ARCHIVE) + .select(create.selectFrom(AUTHOR).where(AUTHOR.DECEASED.isTrue()));
    The UPDATE statement - +

    The UPDATE statement is used to modify one or several pre-existing records in a database table. UPDATE statements are only possible on single tables. Support for multi-table updates will be implemented in the near future. An example update query is given here:

    - + UPDATE AUTHOR SET FIRST_NAME = 'Hermann', LAST_NAME = 'Hesse' - WHERE ID = 3; -create.update(AUTHOR) + WHERE ID = 3;create.update(AUTHOR) .set(AUTHOR.FIRST_NAME, "Hermann") .set(AUTHOR.LAST_NAME, "Hesse") .where(AUTHOR.ID.equal(3)); - + -
    +
    The DELETE statement - +

    The DELETE statement physically removes records from a database table. DELETE statements are only possible on single tables. Support for multi-table deletes will be implemented in the near future. An example delete query is given here:

    - + DELETE AUTHOR - WHERE ID = 100; -create.delete(AUTHOR) + WHERE ID = 100;create.delete(AUTHOR) .where(AUTHOR.ID.equal(100)); - + -
    +
    The 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)

    @@ -2613,15 +2560,14 @@ create.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) 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 {jooq-version}, 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 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(AUTHOR) +WHEN NOT MATCHED THEN INSERT (LAST_NAME) VALUES ('Hitchcock')create.mergeInto(AUTHOR) .using(create().selectOne()) .on(AUTHOR.LAST_NAME.equal("Hitchcock")) .whenMatchedThenUpdate() @@ -2629,39 +2575,38 @@ WHEN NOT MATCHED THEN INSERT (LAST_NAME) VALUES ('Hitchcock') .whenNotMatchedThenInsert(AUTHOR.LAST_NAME) .values("Hitchcock"); - +

    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 AUTHOR (FIRST_NAME, LAST_NAME) KEY (LAST_NAME) -VALUES ('John', 'Hitchcock') -create.mergeInto(AUTHOR, +VALUES ('John', 'Hitchcock')create.mergeInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .key(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

    -
    +
    The TRUNCATE statement - +

    The TRUNCATE statement is the only DDL statement supported by jOOQ so far. It is popular in many databases when you want to bypass constraints for table truncation. Databases may behave differently, when a truncated table is referenced by other tables. For instance, they may fail if records from a truncated table are referenced, even with ON DELETE CASCADE clauses in place. Please, consider your database manual to learn more about its TRUNCATE implementation.

    @@ -2669,44 +2614,42 @@ VALUES ('John', 'Hitchcock') The TRUNCATE syntax is trivial:

    - - TRUNCATE TABLE AUTHOR; - create.truncate(AUTHOR).execute(); - + + TRUNCATE TABLE AUTHOR;create.truncate(AUTHOR).execute(); +

    TRUNCATE is not supported by Ingres and SQLite. jOOQ will execute a DELETE FROM AUTHOR statement instead.

    -
    +
    Table expressions - +

    The following sections explain the various types of table expressions supported by jOOQ

    -
    +
    Generated Tables - +

    Most of the times, when thinking about a you're probably thinking about an actual physical table in your database schema. If you're using jOOQ's , you will have all tables from your database schema available to you as type safe Java objects. You can then use these tables in SQL , or in other , just like any other table expression. An example is given here:

    - + - + .on(AUTHOR.ID.equal(BOOK.AUTHOR_ID));]]>

    The above example shows how AUTHOR and BOOK tables are joined in a . It also shows how you can access physical by dereferencing the relevant Java attributes of their tables. @@ -2714,17 +2657,17 @@ ON (AUTHOR.ID = BOOK.AUTHOR_ID)]]>

    See the manual's section about for more information about what is really generated by the

    -
    +
    Aliased Tables - +

    The strength of jOOQ's becomes more obvious when you perform table aliasing and dereference fields from generated aliased tables. This can best be shown by example:

    - 1920 AND a.first_name = 'Paulo' - ORDER BY b.title]]> - + .orderBy(b.TITLE);]]>

    As you can see in the above example, calling as() on generated tables returns an object of the same type as the table. This means that the resulting object can be used to dereference fields from the aliased table. This is quite powerful in terms of having your Java compiler check the syntax of your SQL statements. If you remove a column from a table, dereferencing that column from that table alias will cause compilation errors. @@ -2755,17 +2697,17 @@ create.select()

    TODO document this

    -
    +
    Joined tables - +

    The that can be used in are the most powerful and best supported means of creating new in SQL. Informally, the following can be said:

    -A(colA1, ..., colAn) "join" B(colB1, ..., colBm) "produces" C(colA1, ..., colAn, colB1, ..., colBm) +A(colA1, ..., colAn) "join" B(colB1, ..., colBm) "produces" C(colA1, ..., colAn, colB1, ..., colBm)

    SQL and relational algebra distinguish between at least the following JOIN types (upper-case: SQL, lower-case: relational algebra): @@ -2783,7 +2725,7 @@ create.select() jOOQ supports all of these JOIN types (except semi-join and anti-join) directly on any :

    - table) // Various overloaded INNER JOINs @@ -2806,41 +2748,40 @@ Table crossJoin(TableLike) // Various overloaded NATURAL JOINs Table naturalJoin(TableLike) Table naturalLeftOuterJoin(TableLike) -Table naturalRightOuterJoin(TableLike)]]> +Table naturalRightOuterJoin(TableLike)]]>

    Note that most of jOOQ's JOIN operations give way to a similar DSL API hierarchy as previously seen in the manual's section about the

    -
    +
    Nested SELECTs - +

    A can appear almost anywhere a can. Such a "nested SELECT" is often called a "derived table". Apart from many convenience methods accepting objects directly, a SELECT statement can always be transformed into a object using the asTable() method.

    Example: Scalar subquery

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

    Example: Derived table

    - + - nested = +]]> nested = create.select(BOOK.AUTHOR_ID, count().as("books")) .from(BOOK) .groupBy(BOOK.AUTHOR_ID).asTable("nested"); @@ -2859,10 +2799,10 @@ ORDER BY nested.books DESC create.select(nested.getFields()) .from(nested) .orderBy(nested.getField("books"));]]> - +

    Example: Correlated subquery

    - + - +]]> Field books = create.selectCount() .from(BOOK) @@ -2882,52 +2821,52 @@ Field books = create.select(AUTHOR.ID, books) .from(AUTHOR) .orderBy(books, AUTHOR.ID));]]> - - + +
    The Oracle 11g PIVOT clause - +

    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 .. +-- SELECT .. FROM table PIVOT (aggregateFunction [, aggregateFunction] FOR column IN (expression [, expression])) --- WHERE .. +-- WHERE ..

    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 slightly different PIVOT clause will be added later. Also, jOOQ may simulate PIVOT for other dialects in the future.

    -
    +
    jOOQ's relational division syntax - +

    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 +Assume the following cross join / cartesian product C = A × B Then it can be said that A = C ÷ B -B = C ÷ A +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) +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" +SELECT DISTINCT C.TEXT FROM C "c1" WHERE NOT EXISTS ( SELECT 1 FROM B WHERE NOT EXISTS ( @@ -2935,7 +2874,7 @@ WHERE NOT EXISTS ( 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. @@ -2949,13 +2888,13 @@ WHERE NOT EXISTS (

  • http://en.wikipedia.org/wiki/Relational_algebra#Division
  • http://www.simple-talk.com/sql/t-sql-programming/divided-we-stand-the-sql-of-relational-division/
  • -
    +
    Array and cursor unnesting - +

    The SQL standard specifies how SQL databases should implement ARRAY and TABLE types, as well as CURSOR types. Put simply, a CURSOR is a pointer to any materialised . Depending on the cursor's features, this table expression can be scrolled through in both directions, records can be locked, updated, removed, inserted, etc. Often, CURSOR types contain s, whereas ARRAY and TABLE types contain simple scalar values, although that is not a requirement

    @@ -2969,21 +2908,20 @@ WHERE NOT EXISTS ( The real power of these types become more obvious when you fetch them from to unnest them as and use them in your . An example is given here, where Oracle's DBMS_XPLAN package is used to fetch a cursor containing data about the most recent execution plan:

    - + - - +

    Note, in order to access the DbmsXplan package, you can use the to generate Oracle's SYS schema.

    -
    +
    The DUAL table - +

    The SQL standard specifies that the is optional in a . However, according to the standard, you may then no longer use some other clauses, such as the . In the real world, there exist three types of databases:

    @@ -2996,7 +2934,7 @@ FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(null, null, 'ALLSTATS'));]]> With jOOQ, you don't have to worry about the above distinction of SQL dialects. jOOQ never requires a FROM clause, but renders the necessary "DUAL" table, if needed. The following program shows how jOOQ renders "DUAL" tables

    - + - - +

    Note, that some databases (H2, MySQL) can normally do without "dual". However, there exist some corner-cases with complex nested SELECT statements, where this will cause syntax errors (or parser bugs). To stay on the safe side, jOOQ will always render "dual" in those dialects.

    -
    +
    Column expressions - +

    Column expressions can be used in various SQL clauses in order to refer to one or several columns. This chapter explains how to form various types of column expressions with jOOQ. A particular type of column expression is given in the section about , where an expression may have a degree of more than one.

    @@ -3046,7 +2983,7 @@ new Factory(SQLDialect.SYBASE ).selectOne().getSQL();]]> jOOQ allows you to freely create arbitrary column expressions using a fluent expression construction API. Many expressions can be formed as functions from , other expressions can be formed based on a pre-existing column expression. For example:

    - field1 = BOOK.TITLE; // A function created from the Factory using "prefix" notation @@ -3058,31 +2995,30 @@ Field field3 = BOOK.TITLE.trim(); // More complex function with advanced DSL syntax Field field4 = listAgg(BOOK.TITLE) .withinGroupOrderBy(BOOK.ID.asc()) - .over().partitionBy(AUTHOR.ID);]]> + .over().partitionBy(AUTHOR.ID);]]>

    In general, it is up to you whether you want to use the "prefix" notation or the "postfix" notation to create new column expressions based on existing ones. The "SQL way" would be to use the "prefix notation", with functions created from the . The "Java way" or "object-oriented way" would be to use the "postfix" notation with functions created from objects. Both ways ultimately create the same query part, though.

    -
    +
    Table columns - +

    Table columns are the most simple implementations of a . They are mainly produced by jOOQ's and can be dereferenced from the generated tables. This manual is full of examples involving table columns. Another example is given in this query:

    - + - - +

    Table columns implement a more specific interface called , which is parameterised with its associated <R extends Record> record type. @@ -3090,45 +3026,43 @@ ORDER BY BOOK.TITLE]]>

    See the manual's section about for more information about what is really generated by the

    -
    +
    Aliased columns - +

    Just like , columns can be renamed using aliases. Here is an example:

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

    Here is how it's done with jOOQ:

    -Record record = create.select( +Record record = create.select( concat(AUTHOR.FIRST_NAME, val(" "), AUTHOR.LAST_NAME).as("author"), count().as("books")) .from(AUTHOR) .join(BOOK).on(AUTHOR.ID.equal(BOOK.AUTHOR_ID)) - .groupBy(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME).fetchAny(); + .groupBy(AUTHOR.FIRST_NAME, 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")); - -
    +System.out.println("Author : " + record.getValue("author")); +System.out.println("Books : " + record.getValue("books"));
    Cast expressions - +

    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.

    @@ -3136,27 +3070,27 @@ System.out.println("Books : " + record.getValue("books")); Sometimes, this automatic mapping might not be what you needed, or jOOQ cannot know the type of a field. In those cases you would write SQL type CASTs like this:

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

    in jOOQ, you can write something like that:

    -create.select(TAuthor.LAST_NAME.cast(PostgresDataType.TEXT)); +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)); +create.select(TAuthor.LAST_NAME.cast(String.class));

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

    - { + { // Cast this field to the type of another field Field cast(Field field); @@ -3176,41 +3110,39 @@ public class Factory { Field castNull(Field field); Field castNull(DataType type); Field castNull(Class type); -}]]> -
    +}]]>
    Arithmetic expressions - +

    Numeric arithmetic expressions

    Your database can do the math for you. 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 +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); +create.select(val(1).add(2).mul(val(5).sub(3)).div(2).mod(10);

    Datetime arithmetic expressions

    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)); - + + 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: @@ -3219,31 +3151,30 @@ public class Factory {

  • INTERVAL YEAR TO MONTH:
  • INTERVAL DAY TO SECOND:
  • -
    +
    String concatenation - +

    The SQL standard defines the concatenation operator to be an infix operator, similar to the ones we've seen in the chapter about . This operator looks like this: ||. Some other dialects do not support this operator, but expect a concat() function, instead. jOOQ renders the right operator / function, depending on your :

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

    There are a variety of general functions supported by jOOQ As discussed in the chapter about functions are mostly simulated in your database, in case they are not natively supported.

    @@ -3260,12 +3191,12 @@ create.select(concat("A", "B", "C"));

    Please refer to the for more details.

    -
    +
    Numeric functions - +

    Math can be done efficiently in the database before returning results to your Java application. In addition to the discussed previously, jOOQ also supports a variety of numeric functions. As discussed in the chapter about numeric functions (as any function type) are mostly simulated in your database, in case they are not natively supported.

    @@ -3307,12 +3238,12 @@ create.select(concat("A", "B", "C"));

    Please refer to the for more details.

    -
    +
    Bitwise functions - +

    Interestingly, bitwise functions and bitwise arithmetic is not very popular among SQL databases. Most databases only support a few bitwise operations, while others ship with the full set of operators. jOOQ's API includes most bitwise operations as listed below. In order to avoid ambiguities with , all bitwise functions are prefixed with "bit"

    @@ -3335,12 +3266,12 @@ create.select(concat("A", "B", "C")); http://blog.jooq.org/2011/10/30/the-comprehensive-sql-bitwise-operations-compatibility-list/

    -
    +
    String functions - +

    String formatting can be done efficiently in the database before returning results to your Java application. As discussed in the chapter about string functions (as any function type) are mostly simulated in your database, in case they are not natively supported.

    @@ -3378,18 +3309,18 @@ create.select(concat("A", "B", "C")); Various databases have some means of searching through columns using regular expressions if the does not provide sufficient pattern matching power. While there are many different functions and operators in the various databases, jOOQ settled for the SQL:2008 standard REGEX_LIKE operator. Being an operator (and not a function), you should use the corresponding method on :

    - +

    Note that the SQL standard specifies that patterns should follow the XQuery standards. In the real world, the POSIX regular expression standard is the most used one, some use Java regular expressions, and only a few ones use Perl regular expressions. jOOQ does not make any assumptions about regular expression syntax. For cross-database compatibility, please read the relevant database manuals carefully, to learn about the appropriate syntax. Please refer to the for more details.

    -
    +
    Date and time functions - +

    This is a list of date and time functions supported by jOOQ's :

    @@ -3408,29 +3339,29 @@ create.select(concat("A", "B", "C"));

    jOOQ fills a gap opened by JDBC, which neglects an important SQL data type as defined by the SQL standards: INTERVAL types. See the manual's section about for more details.

    -
    +
    System functions - +

    This is a list of system functions supported by jOOQ's :

    • CURRENT_USER: Get current user.
    -
    +
    Aggregate functions - +

    Aggregate functions work just like functions, even if they have a slightly different semantics. Here are some example aggregate functions from the :

    - count(); AggregateFunction count(Field field); AggregateFunction max (Field field); @@ -3467,20 +3398,19 @@ AggregateFunction regrR2 (Field y, Field regrSlope (Field y, Field x); AggregateFunction regrSXX (Field y, Field x); AggregateFunction regrSXY (Field y, Field x); -AggregateFunction regrSYY (Field y, Field x);]]> +AggregateFunction regrSYY (Field y, Field x);]]>

    Here's an example, counting the number of books any author has written:

    - + SELECT AUTHOR_ID, COUNT(*) FROM BOOK -GROUP BY AUTHOR_ID -create.select(BOOK.AUTHOR_ID, count()) +GROUP BY AUTHOR_IDcreate.select(BOOK.AUTHOR_ID, count()) .from(BOOK) .groupBy(BOOK.AUTHOR_ID); - +

    Aggregate functions have strong limitations about when they may be used and when not. For instance, you can use aggregate functions in scalar queries. Typically, this means you only select aggregate functions, no or other . Another use case is to use them along with a as seen in the previous example. Note, that jOOQ does not check whether your using of aggregate functions is correct according to the SQL standards, or according to your database's behaviour. @@ -3490,39 +3420,37 @@ GROUP BY AUTHOR_ID

    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 Oracle's LISTAGG() (also known as GROUP_CONCAT in other ). 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, ", ") +GROUP BY AUTHOR_IDcreate.select(listAgg(BOOK.TITLE, ", ") .withinGroupOrderBy(BOOK.TITLE)) .from(BOOK) .groupBy(BOOK.AUTHOR_ID) - +

    The above query might yield:

    -+---------------------+ ++---------------------+ | LISTAGG | +---------------------+ | 1984, Animal Farm | | O Alquimista, Brida | -+---------------------+ ++---------------------+

    FIRST and LAST: Oracle's "ranked" aggregate functions

    Oracle allows for restricting aggregate functions using the KEEP() clause, which is supported by jOOQ. In Oracle, some aggregate functions (MIN, MAX, SUM, AVG, COUNT, VARIANCE, or STDDEV) can be restricted by this clause, hence also allows for specifying it. Here are a couple of examples using this clause:

    - + SUM(BOOK.AMOUNT_SOLD) - KEEP(DENSE_RANK FIRST ORDER BY BOOK.AUTHOR_ID) -sum(BOOK.AMOUNT_SOLD) + KEEP(DENSE_RANK FIRST ORDER BY BOOK.AUTHOR_ID)sum(BOOK.AMOUNT_SOLD) .keepDenseRankFirstOrderBy(BOOK.AUTHOR_ID) - +

    User-defined aggregate functions

    @@ -3533,12 +3461,12 @@ GROUP BY AUTHOR_ID

    In those databases that support , jOOQ's can be transformed into a window function / analytical function by calling over() on it. See the manual's section about for more details.

    -
    +
    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. Note, that H2 and HSQLDB have implemented ROW_NUMBER() functions, without true windowing support.

    @@ -3546,7 +3474,7 @@ GROUP BY AUTHOR_ID As previously discussed, any can be transformed into a window function using the over() method. See the chapter about for details. In addition to those, there are also some more window functions supported by jOOQ, as declared in the :

    - rowNumber(); WindowOverStep rank(); WindowOverStep denseRank(); @@ -3566,7 +3494,7 @@ GROUP BY AUTHOR_ID // Statistical functions WindowOverStep cumeDist(); - WindowOverStep ntile(int number);]]> + WindowOverStep ntile(int number);]]>

    SQL distinguishes between various window function types (e.g. "ranking functions"). Depending on the function, SQL expects mandatory PARTITION BY or ORDER BY clauses within the OVER() clause. jOOQ does not enforce those rules for two reasons: @@ -3583,7 +3511,7 @@ GROUP BY AUTHOR_ID Here are some simple examples of window functions with jOOQ:

    - + -- Sample uses of ROW_NUMBER() ROW_NUMBER() OVER() ROW_NUMBER() OVER(PARTITION BY 1) @@ -3594,8 +3522,7 @@ ROW_NUMBER() OVER(PARTITION BY BOOK.AUTHOR_ID ORDER BY BOOK.ID) FIRST_VALUE(BOOK.ID) OVER() FIRST_VALUE(BOOK.ID IGNORE NULLS) OVER() FIRST_VALUE(BOOK.ID RESPECT NULLS) OVER() - -// Sample uses of rowNumber() +// Sample uses of rowNumber() rowNumber().over() rowNumber().over().partitionByOne() rowNumber().over().partitionBy(BOOK.AUTHOR_ID) @@ -3606,27 +3533,26 @@ firstValue(BOOK.ID).over() firstValue(BOOK.ID).ignoreNulls().over() firstValue(BOOK.ID).respectNulls().over() - +

    An advanced window function example

    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). Window functions are accessible from the previously seen 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, + FROM transactionscreate.select(t.BOOKED_AT, t.AMOUNT, sum(t.AMOUNT).over().partitionByOne() .orderBy(t.BOOKED_AT) .rowsBetweenUnboundedPreceding() .andCurrentRow().as("total") .from(TRANSACTIONS.as("t")); - +

    Window functions created from ordered aggregate functions

    @@ -3634,48 +3560,46 @@ firstValue(BOOK.ID).respectNulls().over() In the previous chapter about , we have seen the concept of "ordered aggregate functions", such as Oracle's LISTAGG(). These functions have a window function / analytical function variant, as well. For example:

    - + SELECT LISTAGG(TITLE, ', ') WITHIN GROUP (ORDER BY TITLE) OVER (PARTITION BY BOOK.AUTHOR_ID) -FROM BOOK -create.select(listAgg(BOOK.TITLE, ", ") +FROM BOOKcreate.select(listAgg(BOOK.TITLE, ", ") .withinGroupOrderBy(BOOK.TITLE) .over().partitionBy(BOOK.AUTHOR_ID)) .from(BOOK) - +

    Window functions created from Oracle's FIRST and LAST aggregate functions

    In the previous chapter about , we have seen the concept of "FIRST and LAST aggregate functions". These functions have a window function / analytical function variant, as well. For example:

    - + SUM(BOOK.AMOUNT_SOLD) KEEP(DENSE_RANK FIRST ORDER BY BOOK.AUTHOR_ID) - OVER(PARTITION BY 1) -sum(BOOK.AMOUNT_SOLD) + OVER(PARTITION BY 1)sum(BOOK.AMOUNT_SOLD) .keepDenseRankFirstOrderBy(BOOK.AUTHOR_ID) .over().partitionByOne() - +

    Window functions created from user-defined aggregate functions

    User-defined aggregate functions also implement , hence they can also be transformed into window functions using over(). This is supported by Oracle in particular. See the manual's section about for more details.

    -
    +
    Grouping functions - +

    ROLLUP() explained in SQL

    The SQL standard defines special functions that can be used in the : the grouping functions. These functions can be used to generate several groupings in a single clause. This can best be explained in SQL. Let's take ROLLUP() for instance:

    - + - - +

    In English, the ROLLUP() grouping function provides N+1 groupings, when N is the number of arguments to the ROLLUP() function. Each grouping has an additional group field from the ROLLUP() argument field list. The results of the second query might look something like this:

    - ++-----------+--------------+----------+]]>

    CUBE() explained in SQL

    CUBE() is different from ROLLUP() in the way that it doesn't just create N+1 groupings, it creates all 2^N possible combinations between all group fields in the CUBE() function argument list. Let's re-consider our second query from before:

    - + - - +

    The results would then hold:

    - ++-----------+--------------+----------+]]>

    GROUPING SETS()

    @@ -3804,7 +3726,7 @@ ORDER BY 1 NULLS FIRST, 2 NULLS FIRST jOOQ fully supports all of these functions, as well as the utility functions GROUPING() and GROUPING_ID(), used for identifying the grouping set ID of a record. The thus includes:

    - rollup(Field... fields); Field cube(Field... fields); Field groupingSets(Field... fields); @@ -3813,66 +3735,64 @@ Field groupingSets(Collection>... fields); // The utility functions generating IDs per GROUPING SET Field grouping(Field); -Field groupingId(Field...);]]> +Field groupingId(Field...);]]>

    MySQL's and CUBRID's WITH ROLLUP syntax

    MySQL and CUBRID don't know any grouping functions, but they support a WITH ROLLUP clause, that is equivalent to simple ROLLUP() grouping functions. jOOQ simulates ROLLUP() in MySQL and CUBRID, by rendering this WITH ROLLUP clause. The following two statements mean the same:

    - + - - -
    + +
    User-defined functions - +

    Some databases support user-defined functions, which can be embedded in any SQL statement, if you're using jOOQ's . Let's say you have the following simple function in Oracle SQL:

    - +]]>

    The above function will be made available from a generated class. You can use it like any other :

    - - - - + + +

    Note that user-defined functions returning or data types can also be used wherever can be used, if they are

    -
    +
    User-defined aggregate functions - +

    Some databases support user-defined aggregate functions, which can then be used along with or as . An example for such a database is Oracle. With Oracle, you can define the following OBJECT type (the example was taken from the Oracle 11g documentation):

    - +END;]]>

    The above OBJECT type is then available to function declarations as such:

    - +PARALLEL_ENABLE AGGREGATE USING U_SECOND_MAX;]]>

    Using the generated aggregate function

    jOOQ's will detect such aggregate functions and generate them differently from regular . They implement the type, as mentioned in the manual's section about . Here's how you can use the SECOND_MAX() aggregate function with jOOQ:

    - + - - -
    + +
    The CASE expression - +

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

    - + - - +

    In jOOQ, both syntaxes are supported (The second one is simulated in Derby, which only knows the first one). 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. @@ -3989,15 +3907,15 @@ create.decode().value(AUTHOR.FIRST_NAME) A CASE expression can be used anywhere where you can place a . For instance, you can SELECT the above expression, if you're selecting from AUTHOR:

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

    The Oracle DECODE() function

    Oracle knows a more succinct, but maybe less readable DECODE() function with a variable number of arguments. This function roughly does the same as the second case expression syntax. jOOQ supports the DECODE() function and simulates it using CASE expressions in all dialects other than Oracle:

    - + - - +

    CASE clauses in an ORDER BY clause

    Sort indirection is often implemented with a CASE clause of a SELECT's ORDER BY clause. See the manual's section about the for more details.

    -
    +
    Sequences and serials - +

    Sequences implement the interface, providing essentially this functionality:

    - currval(); // Get a field for the NEXTVAL sequence property -Field nextval();]]> +Field nextval();]]>

    So if you have a sequence like this in Oracle:

    -CREATE SEQUENCE s_author_id +CREATE SEQUENCE s_author_id

    You can then use your object directly in a SQL statement as such:

    - +]]>
    • For more information about generated sequences, refer to the manual's section about
    • For more information about executing standalone calls to sequences, refer to the manual's section about
    -
    +
    Tuples or row value expressions - +

    According to the SQL standard, row value expressions can have a degree of more than one. This is commonly used in the , where the VALUES row value constructor allows for providing a row value expression as a source for INSERT data. Row value expressions can appear in various other places, though. They are supported by jOOQ as s / rows. jOOQ's allows for the construction of type-safe s up to the degree / arity of 8. Higher-degree s are supported as well, but without any type-safety. types are modelled as follows:

    - Row1 row(T1 t1) { ... } public static Row2 row(T1 t1, T2 t2) { ... } public static Row3 row(T1 t1, T2 t2, T3 t3) { ... } @@ -4082,7 +3999,7 @@ public static Row4 row(T1 t1, T2 t2, T3 t3, T4 // [ ... idem for Row5, Row6, Row7, Row8 ... ] // Degrees of more than 8 are supported without type-safety -public static RowN row(Object... values) { ... }]]> +public static RowN row(Object... values) { ... }]]>

    Using row value expressions in predicates

    @@ -4093,14 +4010,14 @@ public static RowN row(Object... values) { ... }]]>

    The also supports a variant where row value expressions are updated, rather than single columns. See the relevant section for more details

    -
    +
    Conditional expressions - +

    Conditions or conditional expressions are widely used in SQL and in the jOOQ API. They can be used in

    @@ -4137,22 +4054,21 @@ public static RowN row(Object... values) { ... }]]>

    Note that jOOQ does not model these values as actual compatible.

    -
    +
    Condition building - +

    With jOOQ, most are built from , calling various methods on them. For instance, to build a , you can write the following expression:

    - + - - +

    Create conditions from the Factory

    @@ -4168,48 +4084,47 @@ BOOK.TITLE.notEqual("Animal Farm")]]>

    Conditions can also be connected using as will be discussed in a subsequent chapter.

    -
    +
    AND, OR, NOT boolean operators - +

    In SQL, as in most other languages, can be connected using the AND and OR binary operators, as well as the NOT unary operator, to form new conditional expressions. In jOOQ, this is modelled as such:

    - + - - +

    The above example shows that the number of parentheses in Java can quickly explode. Proper indentation may become crucial in making such code readable. In order to understand how jOOQ composes combined conditional expressions, let's assign component expressions first:

    - +Condition combined2 = combined1.andNot(c); // The left-hand side of the AND NOT () operator is already wrapped in parentheses]]>

    The Condition API

    Here are all boolean operators on the interface:

    -) // Combine conditions with OR. Convenience for adding orNot(Condition) // Combine conditions with OR. Convenience for adding an inverted condition to the rhs orNotExists(Select) // Combine conditions with OR. Convenience for adding an inverted exists predicate to the rhs -not() // Invert a condition (synonym for Factory.not(Condition)]]> -
    +not() // Invert a condition (synonym for Factory.not(Condition)]]>
    Comparison predicate - +

    In SQL, comparison predicates are formed using common comparison operators:

    @@ -4248,7 +4162,7 @@ not() // Invert a condition (synonym for Factory.not(Conditi Unfortunately, Java does not support operator overloading, hence these operators are also implemented as methods in jOOQ, like any other SQL syntax elements. The relevant parts of the interface are these:

    -); // = (some column expression) eq or equal(Select); // = (some scalar SELECT statement) ne or notEqual(T); // <> (some bind value) @@ -4265,7 +4179,7 @@ gt or greaterThan(Field); // > (some column expression) gt or greaterThan(Select); // > (some scalar SELECT statement) ge or greaterOrEqual(T); // >= (some bind value) ge or greaterOrEqual(Field); // >= (some column expression) -ge or greaterOrEqual(Select); // >= (some scalar SELECT statement)]]> +ge or greaterOrEqual(Select); // >= (some scalar SELECT statement)]]>

    Note that every operator is represented by two methods. A verbose one (such as equal()) and a two-character one (such as eq()). Both methods are the same. You may choose either one, depending on your taste. The manual will always use the more verbose one. @@ -4281,30 +4195,28 @@ ge or greaterOrEqual(Select); // >= (some scalar SELECT statement)]]> In addition to the above, jOOQ provides a few convenience methods for common operations performed on strings using comparison predicates:

    - + LOWER('animal farm')]]> - LOWER('animal farm')]]> - -
    + +
    Quantified comparison predicate - +

    If the right-hand side of a turns out to be a non-scalar table subquery, you can wrap that subquery in a quantifier, such as ALL, ANY, or SOME. Note that the SQL standard defines ANY and SOME to be equivalent. jOOQ settled for the more intuitive ANY and doesn't support SOME. Here are some examples, supported by jOOQ:

    - + ALL(1920, 1940)]]> - ALL(1920, 1940)]]> - +

    For the example, the right-hand side of the quantified comparison predicates were filled with argument lists. But it is easy to imagine that the source of values results from a . @@ -4315,37 +4227,35 @@ BOOK.PUBLISHED_IN.greaterThanAll(1920, 1940);]]> It is interesting to note that the SQL standard defines the in terms of the ANY-quantified predicate. The following two expressions are equivalent:

    - - - - + + +

    Typically, the is more readable than the quantified comparison predicate.

    -
    +
    NULL predicate - +

    In SQL, you cannot compare NULL with any value using , as the result would yield NULL again, which is neither TRUE nor FALSE (see also the manual's section about ). In order to test a for NULL, use the NULL predicate as such:

    - + - - + -
    +
    DISTINCT predicate - +

    Some databases support the DISTINCT predicate, which serves as a convenient, NULL-safe . With the DISTINCT predicate, the following truth table can be assumed:

    @@ -4359,18 +4269,17 @@ BOOK.TITLE.isNotNull()]]> For instance, you can compare two fields for distinctness, ignoring the fact that any of the two could be NULL, which would lead to funny results. This is supported by jOOQ as such:

    - + - - +

    If your database does not natively support the DISTINCT predicate, jOOQ simulates it with an equivalent , modelling the above truth table:

    - + - - -
    + +
    BETWEEN predicate - +

    The BETWEEN predicate can be seen as syntactic sugar for a pair of . According to the SQL standard, the following two predicates are equivalent:

    - - -= [B] AND [A] <= [C]]]> - + += [B] AND [A] <= [C]]]> +

    Note the inclusiveness of range boundaries in the definition of the BETWEEN predicate. Intuitively, this is supported in jOOQ as such:

    - + - - +

    BETWEEN SYMMETRIC

    The SQL standard defines the SYMMETRIC keyword to be used along with BETWEEN to indicate that you do not care which bound of the range is larger than the other. A database system should simply swap range bounds, in case the first bound is greater than the second one. jOOQ supports this keyword as well, simulating it if necessary.

    - + - - +

    The simulation is done trivially:

    - - - - + + + -
    +
    LIKE predicate - +

    LIKE predicates are popular for simple wildcard-enabled pattern matching. Supported wildcards in all SQL databases are:

    @@ -4452,24 +4356,22 @@ BOOK.PUBLISHED_IN.notBetweenSymmetric(1940).and(1920)]]> With jOOQ, the LIKE predicate can be created from any as such:

    - + - - +

    Escaping operands with the LIKE predicate

    Often, your pattern may contain any of the wildcard characters "_" and "%", in case of which you may want to escape them. jOOQ does not automatically escape patterns in like() and notLike() methods. Instead, you can explicitly define an escape character as such:

    - + - - +

    In the above predicate expressions, the exclamation mark character is passed as the escape character to escape wildcard characters "!_" and "!%", as well as to escape the escape character itself: "!!" @@ -4483,7 +4385,7 @@ BOOK.TITLE.notLike("%The !%-Sign Book%", '!')]]> In addition to the above, jOOQ provides a few convenience methods for common operations performed on strings using the LIKE predicate. Typical operations are "contains predicates", "starts with predicates", "ends with predicates", etc. Here is the full convenience API wrapping LIKE predicates:

    - + - - +

    Note, that jOOQ escapes % and _ characters in value in some of the above predicate implementations. For simplicity, this has been omitted in this manual.

    -
    +
    IN predicate - +

    In SQL, apart from comparing a value against several values, the IN predicate can be used to create semi-joins or anti-joins. jOOQ knows the following methods on the interface, to construct such IN predicates:

    -) // Construct an IN predicate from a collection of bind values +) // Construct an IN predicate from a collection of bind values in(T...) // Construct an IN predicate from bind values in(Field...) // Construct an IN predicate from column expressions in(Select) // Construct an IN predicate from a subselect notIn(Collection) // Construct a NOT IN predicate from a collection of bind values notIn(T...) // Construct a NOT IN predicate from bind values notIn(Field...) // Construct a NOT IN predicate from column expressions -notIn(Select) // Construct a NOT IN predicate from a subselect]]> +notIn(Select) // Construct a NOT IN predicate from a subselect]]>

    A sample IN predicate might look like this:

    - + - - +

    NOT IN and NULL values

    @@ -4541,7 +4441,7 @@ BOOK.TITLE.notIn("Animal Farm", "1984")]]> Beware that you should probably not have any NULL values in the right hand side of a NOT IN predicate, as the whole expression would evaluate to NULL, which is rarely desired. This can be shown informally using the following reasoning:

    --- The following conditional expressions are formally or informally equivalent +-- The following conditional expressions are formally or informally equivalent A NOT IN (B, C) A != ANY(B, C) A != B AND A != C @@ -4550,17 +4450,17 @@ A != B AND A != C A NOT IN (B, NULL) -- Substitute C for NULL A != B AND A != NULL -- From the above rules A != B AND NULL -- [ANY] != NULL yields NULL -NULL -- [ANY] AND NULL yields NULL +NULL -- [ANY] AND NULL yields NULL

    A good way to prevent this from happening is to use the for anti-joins, which is NULL-value insensitive. See the manual's section about to see a boolean truth table.

    -
    +
    EXISTS predicate - +

    Slightly less intuitive, yet more powerful than the previously discussed is the EXISTS predicate, that can be used to form semi-joins or anti-joins. With jOOQ, the EXISTS predicate can be formed in various ways:

    @@ -4574,16 +4474,15 @@ NULL -- [ANY] AND NULL yields NULL An example of an EXISTS predicate can be seen here:

    - + - - +

    Note that in SQL, the projection of a subselect in an EXISTS predicate is irrelevant. To help you write queries like the above, you can use jOOQ's selectZero() or selectOne() methods @@ -4594,60 +4493,59 @@ notExists(create.selectOne().from(BOOK) In theory, the two types of predicates can perform equally well. If your database system ships with a sophisticated cost-based optimiser, it will be able to transform one predicate into the other, if you have all necessary constraints set (e.g. referential constraints, not null constraints). However, in reality, performance between the two might differ substantially. An interesting blog post investigating this topic on the MySQL database can be seen here:
    http://blog.jooq.org/2012/07/27/not-in-vs-not-exists-vs-left-join-is-null-mysql/

    -
    +
    OVERLAPS predicate - +

    When comparing dates, the SQL standard allows for using a special OVERLAPS predicate, which checks whether two date ranges overlap each other. The following can be said:

    - +(DATE '2010-01-02', CAST('+2 00:00:00' AS INTERVAL DAY TO SECOND))]]>

    The OVERLAPS predicate in jOOQ

    jOOQ supports the OVERLAPS predicate on . The following methods are contained in :

    - t1, Field t2); -Condition overlaps(Row2 row);]]> +Condition overlaps(Row2 row);]]>

    This allows for expressing the above predicates as such:

    - +row(Date.valueOf('2010-01-01'), new DayToSecond(2)).overlaps(Date.valueOf('2010-01-02'), new DayToSecond(2))]]>

    jOOQ's extensions to the standard

    Unlike the standard (or any database implementing the standard), jOOQ also supports the OVERLAPS predicate for comparing arbitrary . For instance, (1, 3) OVERLAPS (2, 4) will yield true in jOOQ. This is simulated as such

    - -
    +(C <= B) AND (A <= D)]]>
    Plain SQL - +

    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 a host language (Java in this case), which was not made for exactly the same purposes as its hosted 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 by language constraints of its host language. We have seen many functionalities where the DSL becomes a bit verbose. This can be especially true for:

    @@ -4676,7 +4574,7 @@ row(Date.valueOf('2010-01-01'), new DayToSecond(2)).overlaps(Date.valueOf('2010-

    Plain SQL API methods are usually overloaded in three ways. Let's look at the condition query part constructor:

    - +Condition condition(String sql, QueryPart... parts);]]>

    Please refer to the Javadoc for more details. The following is a more complete listing of plain SQL construction methods from the Factory:

    - resultQuery(String sql, QueryPart... parts); // A query with results. This is the same as resultQuery(...).fetch(); Result fetch(String sql); Result fetch(String sql, Object... bindings); -Result fetch(String sql, QueryPart... parts);]]> +Result fetch(String sql, QueryPart... parts);]]>

    Apart from the general factory methods, plain SQL is also available 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"); @@ -4772,7 +4670,7 @@ create.select(LAST_NAME, COUNT1, COUNT2) // Use plain SQL again as fields in GROUP BY and ORDER BY clauses .groupBy(LAST_NAME) - .orderBy(LAST_NAME);]]> + .orderBy(LAST_NAME);]]>

    Important things to note about plain SQL!

    @@ -4784,12 +4682,12 @@ create.select(LAST_NAME, COUNT1, COUNT2)

  • 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.
  • -
    +
    Bind values and parameters - +

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

    @@ -4808,31 +4706,31 @@ create.select(LAST_NAME, COUNT1, COUNT2)

    The following sections explain how you can introduce bind values in jOOQ, and how you can control the way they are rendered and bound to SQL.

    -
    +
    Indexed parameters - +

    JDBC only knows indexed bind values. A typical example for using bind values with JDBC is this:

    - +stmm.executeQuery();]]>

    With dynamic SQL, keeping track of the number of question marks and their corresponding index may turn out to be hard. jOOQ abstracts this and lets you provide the bind value right where it is needed. A trivial example is this:

    - +create.select().from(BOOK).where(BOOK.ID.equal(val(5))).and(BOOK.TITLE.equal(val("Animal Farm")));]]>

    Note the using of to explicitly create an indexed bind value. You don't have to worry about that index. When the query is , each bind value will render a question mark. When the query , each bind value will generate the appropriate bind value index. @@ -4843,7 +4741,7 @@ create.select().from(BOOK).where(BOOK.ID.equal(val(5))).and(BOOK.TITLE.equal(val Should you decide to run the above query outside of jOOQ, using your own , you can do so as follows:

    - select = create.select().from(BOOK).where(BOOK.ID.equal(5)).and(BOOK.TITLE.equal("Animal Farm")); + select = create.select().from(BOOK).where(BOOK.ID.equal(5)).and(BOOK.TITLE.equal("Animal Farm")); // Render the SQL statement: String sql = select.getSQL(); @@ -4853,34 +4751,34 @@ assertEquals("SELECT * FROM BOOK WHERE ID = ? AND TITLE = ?", sql); List values = select.getBindValues(); assertEquals(2, values.size()); assertEquals(5, values.get(0)); -assertEquals("Animal Farm", values.get(1));]]> +assertEquals("Animal Farm", values.get(1));]]>

    You can also extract specific bind values by index from a query, if you wish to modify their underlying value after creating a query. This can be achieved as such:

    - select = create.select().from(BOOK).where(BOOK.ID.equal(5)).and(BOOK.TITLE.equal("Animal Farm")); + select = create.select().from(BOOK).where(BOOK.ID.equal(5)).and(BOOK.TITLE.equal("Animal Farm")); Param param = select.getParam("2"); // You could now modify the Query's underlying bind value: if ("Animal Farm".equals(param.getValue())) { param.setConverted("1984"); -}]]> +}]]>

    For more details about jOOQ's internals, see the manual's section about .

    - +
    Named parameters - +

    Some SQL access abstractions that are built on top of JDBC, or some that bypass JDBC may support named parameters. jOOQ allows you to give names to your parameters as well, although those names are not rendered to SQL strings by default. Here is an example of how to create named parameters using the type:

    - param1 = query.getParam("lastName"); @@ -4889,41 +4787,40 @@ Param param2 = param("lastName", "Poe"); Query query2 = create.select().from(AUTHOR).where(LAST_NAME.equal(param2)); // You can now change the bind value directly on the Param reference: -param2.setValue("Orwell");]]> +param2.setValue("Orwell");]]>

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

    - +query2.bind("lastName", "Orwell");]]>

    In order to actually render named parameter names in generated SQL, use the method:

    - + - - -
    + +
    Inlined parameters - +

    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:

    @@ -4939,7 +4836,7 @@ WHERE LAST_NAME = :lastName]]> In both cases, your inlined bind values will be properly escaped to avoid SQL syntax errors and SQL injection. Some examples:

    - -
    + .where(LAST_NAME.equal("Poe"));]]>
    SQL injection and plain SQL QueryParts - +

    Special care needs to be taken when using . While jOOQ's API allows you to specify bind values for use with plain SQL, you're not forced to do that. For instance, both of the following queries will lead to the same, valid result:

    - +create.fetch("SELECT * FROM BOOK WHERE ID = 5 AND TITLE = 'Animal Farm'");]]>

    All methods in the jOOQ API that allow for plain (unescaped, untreated) SQL contain a warning message in their relevant Javadoc, to remind you of the risk of SQL injection in what is otherwise a SQL-injection-safe API.

    -
    +
    QueryParts - +

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

    @@ -5001,12 +4897,12 @@ create.fetch("SELECT * FROM BOOK WHERE ID = 5 AND TITLE = 'Animal Farm'");]]> The following sections explain some more details about and , as well as other implementation details about QueryParts in general.

    -
    +
    SQL rendering - +

    Every must implement the method to render its SQL string to a . This RenderContext has two purposes:

    @@ -5018,7 +4914,7 @@ create.fetch("SELECT * FROM BOOK WHERE ID = 5 AND TITLE = 'Animal Farm'");]]> API is given here:

    - +RenderContext castModeSome(SQLDialect... dialects);]]>

    The following additional methods are inherited from a common , which is shared among and :

    - +int peekIndex();]]>

    An example of rendering SQL

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

    --- [...] +-- [...] FROM AUTHOR JOIN BOOK ON AUTHOR.ID = BOOK.AUTHOR_ID --- [...] +-- [...]

    This is how jOOQ renders such a condition:

    - +}]]>

    See the manual's sections about and to learn about how to write your own query parts in order to extend jOOQ.

    -
    +
    Pretty printing SQL - +

    As mentioned in the previous chapter about , there are some elements in the that are used for formatting / pretty-printing rendered SQL. In order to obtain pretty-printed SQL, just use the following :

    - +

    And then, use the above factory to render pretty-printed SQL:

    - + - '1984' group by "TEST"."AUTHOR"."LAST_NAME" having count(*) = 2]]> - +

    The section about shows an example of how such pretty printing can be used to log readable SQL to the stdout.

    -
    +
    Variable binding - +

    Every must implement the method. This BindContext has two purposes:

    @@ -5183,7 +5078,7 @@ having count(*) = 2]]> An overview of the API is given here:

    - type) throws DataAccessException; -BindContext bindValues(Object... values) throws DataAccessException;]]> +BindContext bindValues(Object... values) throws DataAccessException;]]>

    Some additional methods are inherited from a common , which is shared among and . Details are documented in the previous chapter about @@ -5204,43 +5099,43 @@ BindContext bindValues(Object... values) throws DataAccessException;]]> A simple example can be provided by checking out jOOQ's internal representation of a (simplified) . It is used for any comparing two fields as for example the AUTHOR.ID = BOOK.AUTHOR_ID condition here:

    --- [...] +-- [...] WHERE AUTHOR.ID = ? --- [...] +-- [...]

    This is how jOOQ binds values on such a condition:

    - +}]]>

    See the manual's sections about and to learn about how to write your own query parts in order to extend jOOQ.

    -
    +
    Extend jOOQ with custom types - +

    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:

    - extends AbstractField {} + extends AbstractField {} public abstract class CustomCondition extends AbstractCondition {} public abstract class CustomTable> extends TableImpl {} -public abstract class CustomRecord> extends TableRecordImpl {}]]> +public abstract class CustomRecord> extends TableRecordImpl {}]]>

    These classes are declared public and covered by jOOQ's integration tests. When you extend these classes, you will have to provide your own implementations for the and methods, as discussed before:

    - +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. Here's an example showing how to create a field multiplying another field by 2

    - IDx2 = new CustomField(BOOK.ID.getName(), BOOK.ID.getDataType()) { @Override public void toSQL(RenderContext context) { @@ -5290,13 +5185,12 @@ final Field IDx2 = new CustomField(BOOK.ID.getName(), BOOK.ID. }; // Use the above field in a SQL statement: -create.select(IDx2).from(BOOK);]]> -
    +create.select(IDx2).from(BOOK);]]>
    Plain SQL QueryParts - +

    If you don't need the 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. Plain SQL methods in jOOQ's API come in two flavours.

    @@ -5308,29 +5202,29 @@ create.select(IDx2).from(BOOK);]]> The above distinction is best explained using an example:

    - id = val(5); Field title = val("Animal Farm"); -create.selectFrom(BOOK).where("BOOK.ID = {0} AND TITLE = {1}", id, title);]]> +create.selectFrom(BOOK).where("BOOK.ID = {0} AND TITLE = {1}", id, title);]]>

    The above technique allows for creating rather complex SQL clauses that are currently not supported by jOOQ, without extending any of the as indicated in the previous chapter.

    -
    +
    Serializability - +

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

    - select = (Select) in.readObject(); @@ -5339,20 +5233,20 @@ select.execute(); // In order to execute the above select, attach it first Factory create = new Factory(connection, SQLDialect.ORACLE); -create.attach(select);]]> +create.attach(select);]]>

    Automatically attaching QueryParts

    Another way of attaching QueryParts automatically, or rather providing them with a new at will, is to hook into the . More details about this can be found in the manual's chapter about

    -
    +
    SQL building in Scala - +

    jOOQ-Scala is a maven module used for leveraging some advanced Scala features for those users that wish to use jOOQ with Scala.

    @@ -5365,7 +5259,7 @@ create.attach(select);]]> The following depicts a trait which wraps all fields:

    -(value : T) : Condition def <=>(value : Field[T]) : Condition -}]]> +}]]>

    The following depicts a trait which wraps numeric fields:

    ->(value : T) : Field[T] def >>(value : Field[T]) : Field[T] -}]]> +}]]>

    An example query using such overloaded operators would then look like this:

    - 2) or (T_BOOK.TITLE in ("O Alquimista", "Brida")) -fetch]]> +fetch]]>

    Scala 2.10 Macros

    This feature is still being experimented with. With Scala Macros, it might be possible to inline a true SQL dialect into the Scala syntax, backed by the jOOQ API. Stay tuned!

    -
    +
    SQL execution - +

    In a previous section of the manual, we've seen how jOOQ can be used to that can be executed with any API including JDBC or ... jOOQ. This section of the manual deals with various means of actually executing SQL with jOOQ.

    @@ -5512,12 +5406,12 @@ fetch]]>

    The following sections of this manual will show how jOOQ is wrapping JDBC for SQL execution

    -
    +
    Comparison between jOOQ and JDBC - +

    Similarities with JDBC

    Even if there are , there are a lot of similarities between JDBC and jOOQ. Just to name a few: @@ -5539,29 +5433,28 @@ fetch]]>

  • : jOOQ does not formally distinguish between static statements and prepared statements. By default, all statements are prepared statements in jOOQ, internally. Executing a statement as a static statement can be done simply using a
  • : JDBC keeps open resources even if they are already consumed. With JDBC, there is a lot of verbosity around safely closing resources. In jOOQ, resources are closed after consumption, by default. If you want to keep them open after consumption, you have to explicitly say so.
  • -
    +
    Query vs. ResultQuery - +

    Unlike JDBC, jOOQ has a lot of knowledge about a SQL query's structure and internals (see the manual's section about ). Hence, jOOQ distinguishes between these two fundamental types of queries. While every can be executed, only can return results (see the manual's section about to learn more about fetching results). With plain SQL, the distinction can be made clear most easily:

    - resultQuery = create.resultQuery("SELECT * FROM BOOK"); -Result resultQuery.fetch();]]> -
    +Result resultQuery.fetch();]]>
    Fetching - +

    Fetching is something that has been completely neglegted by JDBC and also by various other database abstraction libraries. Fetching is much more than just looping or listing records or mapped objects. There are so many ways you may want to fetch data from a database, it should be considered a first-class feature of any database abstraction API. Just to name a few, here are some of jOOQ's fetching modes:

    @@ -5586,7 +5479,7 @@ Result resultQuery.fetch();]]> These modes of fetching are also documented in subsequent sections of the manual

    - fetch(); // The "standard" fetch when you know your query returns only one record @@ -5613,14 +5506,14 @@ List> fetchMany(); List fetch(RecordMapper mapper); // Execute a ResultQuery with jOOQ, but return a JDBC ResultSet, not a jOOQ object -ResultSet fetchResultSet();]]> +ResultSet fetchResultSet();]]>

    Fetch convenience

    These means of fetching are also available from and APIs

    - List fetch(Field field); List fetch(Field field, Class type); @@ -5654,14 +5547,14 @@ ResultSet fetchResultSet();]]> U fetchOne(int fieldIndex, Converter converter); Object fetchOne(String fieldName); T fetchOne(String fieldName, Class type); - U fetchOne(String fieldName, Converter converter);]]> + U fetchOne(String fieldName, Converter converter);]]>

    Fetch transformations

    These means of fetching are also available from and APIs

    - List fetchInto(Class type); // Transform your records into another table type - Result fetchInto(Table table);]]> + Result fetchInto(Table table);]]>

    Note, that apart from the methods, all fetch() methods will immediately close underlying JDBC result sets.

    -
    +
    Record vs. TableRecord - +

    jOOQ understands that SQL is much more expressive than Java, when it comes to the declarative typing of . As a declarative language, SQL allows for creating ad-hoc row value expressions (records with indexed columns) and records (records with named columns). In Java, this is not possible to the same extent. Yet, still, sometimes you wish to use strongly typed records, when you know that you're selecting only from a single table

    @@ -5707,12 +5600,12 @@ ResultSet fetchResultSet();]]> When fetching data only from a single table, the type is known to jOOQ if you use jOOQ's to generate for your database tables. In order to fetch such strongly typed records, you will have to use the :

    - +System.out.println("Published in: " + book.getPublishedIn());]]>

    When you use the method, jOOQ will return the record type supplied with the argument table. Beware though, that you will no longer be able to use any clause that modifies the type of your . This includes: @@ -5723,17 +5616,17 @@ System.out.println("Published in: " + book.getPublishedIn());]]>

  • -
    +
    Arrays, Maps and Lists - +

    By default, jOOQ returns an object, which is essentially a of . Often, you will find yourself wanting to transform this result object into a type that corresponds more to your specific needs. Or you just want to list all values of one specific column. Here are some examples to illustrate those use cases:

    - titles1 = create.select().from(BOOK).fetch().getValues(BOOK.TITLE); List titles2 = create.select().from(BOOK).fetch(BOOK.TITLE); String[] titles3 = create.select().from(BOOK).fetchArray(BOOK.TITLE); @@ -5753,22 +5646,22 @@ Map map4 = create.selectFrom(BOOK).fetchMap(BOOK.ID, BOOK.T Map> group1 = create.selectFrom(BOOK).fetch().intoGroups(BOOK.AUTHOR_ID); Map> group2 = create.selectFrom(BOOK).fetchGroups(BOOK.AUTHOR_ID); Map> group3 = create.selectFrom(BOOK).fetch().intoGroups(BOOK.AUTHOR_ID, BOOK.TITLE); -Map> group4 = create.selectFrom(BOOK).fetchGroups(BOOK.AUTHOR_ID, BOOK.TITLE);]]> +Map> group4 = create.selectFrom(BOOK).fetchGroups(BOOK.AUTHOR_ID, BOOK.TITLE);]]>

    Note that most of these convenience methods are available both through and , some are even available through as well.

    -
    +
    RecordHandler - +

    In a more functional operating mode, you might want to write callbacks that receive records from your select statement results in order to do some processing. This is a common data access pattern in Spring's JdbcTemplate, and it is also available in jOOQ. With jOOQ, you can implement your own classes and plug them into jOOQ's :

    - { Util.doThingsWithBook(book); }; ); -]]> +]]>

    See also the manual's section about the , which provides similar features

    -
    +
    RecordMapper - +

    In a more functional operating mode, you might want to write callbacks that map records from your select statement results in order to do some processing. This is a common data access pattern in Spring's JdbcTemplate, and it is also available in jOOQ. With jOOQ, you can implement your own classes and plug them into jOOQ's :

    - ids = create.selectFrom(BOOK) .orderBy(BOOK.ID) @@ -5824,17 +5717,17 @@ create.selectFrom(BOOK) create.selectFrom(BOOK) .orderBy(BOOK.ID) .fetch(book -> book.getId()); -]]> +]]>

    See also the manual's section about the , which provides similar features

    -
    +
    POJOs - +

    Fetching data in records is fine as long as your application is not really layered, or as long as you're still writing code in the DAO layer. But if you have a more advanced application architecture, you may not want to allow for jOOQ artefacts to leak into other layers. You may choose to write POJOs (Plain Old Java Objects) as your primary DTOs (Data Transfer Objects), without any dependencies on jOOQ's types, which may even potentially hold a reference to a , and thus a JDBC . Like Hibernate/JPA, jOOQ allows you to operate with POJOs. Unlike Hibernate/JPA, jOOQ does not "attach" those POJOs or create proxies with any magic in them.

    @@ -5847,7 +5740,7 @@ create.selectFrom(BOOK) jOOQ tries to find JPA annotations on your POJO types. If it finds any, they are used as the primary source for mapping meta-information. Only the annotation is used and understood by jOOQ. An example:

    - myBooks = create.select().from(BOOK).fetch().into(MyBook.class); -List myBooks = create.select().from(BOOK).fetchInto(MyBook.class);]]> +List myBooks = create.select().from(BOOK).fetchInto(MyBook.class);]]>

    Just as with any other JPA implementation, you can put the annotation on any class member, including attributes, setters and getters. Please refer to the Javadoc for more details. @@ -5870,7 +5763,7 @@ List myBooks = create.select().from(BOOK).fetchInto(MyBook.class);]]> - myBooks = create.select().from(BOOK).fetch().into(MyBook1.class); -List myBooks = create.select().from(BOOK).fetchInto(MyBook1.class);]]> +List myBooks = create.select().from(BOOK).fetchInto(MyBook1.class);]]>

    Please refer to the Javadoc for more details. @@ -5890,7 +5783,7 @@ List myBooks = create.select().from(BOOK).fetchInto(MyBook1.class);]]>< If jOOQ does not find any default constructor, columns are mapped to the "best-matching" constructor. This allows for using "immutable" POJOs with jOOQ. An example illustrates this:

    - myBooks = create.select(BOOK.ID, BOOK.AUTHOR_ID).from(BOOK).fetch().into(MyBook3.class); List myBooks = create.select(BOOK.ID, BOOK.AUTHOR_ID).from(BOOK).fetchInto(MyBook3.class); -]]> +]]>

    Please refer to the Javadoc for more details. @@ -5934,7 +5827,7 @@ List myBooks = create.select(BOOK.ID, BOOK.AUTHOR_ID).from(BOOK).fetchI jOOQ also allows for fetching data into abstract classes or interfaces, or in other words, "proxyable" types. This means that jOOQ will return a wrapped in a implementing your custom type. An example of this is given here:

    - myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetch().into(MyBook3.class); -List myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchInto(MyBook3.class);]]> +List myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchInto(MyBook3.class);]]>

    Please refer to the Javadoc for more details. @@ -5957,7 +5850,7 @@ List myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchInto( The above examples show how to fetch data into your own custom POJOs / DTOs. When you have modified the data contained in POJOs, you probably want to store those modifications back to the database. An example of this is given here:

    - +create.executeUpdate(book);]]>

    Note: Because of your manual setting of ID = 10, jOOQ's store() method will asume that you want to insert a new record. See the manual's section about for more details on this. @@ -5989,7 +5882,7 @@ create.executeUpdate(book);]]> If you're using jOOQ's , you can configure it to for you. Those DAOs operate on . An example of using such a DAO is given here:

    - +bookDao.delete(book);]]>

    More complex data structures

    jOOQ currently doesn't support more complex data structures, the way Hibernate/JPA attempt to map relational data onto POJOs. While future developments in this direction are not excluded, jOOQ claims that generic mapping strategies lead to an enormous additional complexity that only serves very few use cases. You are likely to find a solution using any of jOOQ's various , with only little boiler-plate code on the client side.

    -
    +
    Lazy fetching - +

    Unlike JDBC's , jOOQ's does not represent an open database cursor with various fetch modes and scroll modes, that needs to be closed after usage. jOOQ's results are simple in-memory Java objects, containing all of the result values. If your result sets are large, or if you have a lot of network latency, you may wish to fetch records one-by-one, or in small chunks. jOOQ supports a type for that purpose. In order to obtain such a reference, use the method. An example is given here:

    - cursor = null; try { @@ -6039,7 +5932,7 @@ finally { if (cursor != null) { cursor.close(); } -}]]> +}]]>

    As a holds an internal reference to an open , it may need to be closed at the end of iteration. If a cursor is completely scrolled through, it will conveniently close the underlying ResultSet. However, you should not rely on that. @@ -6055,16 +5948,16 @@ finally {

  • : You can use your own callbacks to map lazily fetched records.
  • : You can fetch data into your own custom POJO types.
  • -
    +
    Many fetching - +

    Many databases support returning several result sets, or cursors, from single queries. An example for this is Sybase ASE's sp_help command:

    - sp_help 'author' + sp_help 'author' +--------+-----+-----------+-------------+-------------------+ |Name |Owner|Object_type|Object_status|Create_date | @@ -6080,14 +5973,14 @@ finally { |last_name |varchar| 50|NULL| NULL| 0| |date_of_birth|date | 4|NULL| NULL| 1| |year_of_birth|int | 4|NULL| NULL| 1| -+-------------+-------+------+----+-----+-----+]]> ++-------------+-------+------+----+-----+-----+]]>

    The correct (and verbose) way to do this with JDBC is as follows:

    - +statement.close();]]>

    As previously discussed in the chapter about , jOOQ does not rely on an internal state of any JDBC object, which is "externalised" by Javadoc. Instead, it has a straight-forward API allowing you to do the above in a one-liner:

    -> results = create.fetchMany("sp_help 'author'");]]> +> results = create.fetchMany("sp_help 'author'");]]>

    Using generics, the resulting structure is immediately clear.

    -
    +
    Later fetching - +

    Some queries take very long to execute, yet they are not crucial for the continuation of the main program. For instance, you could be generating a complicated report in a Swing application, and while this report is being calculated in your database, you want to display a background progress bar, allowing the user to pursue some other work. This can be achived simply with jOOQ, by creating a , a type that extends . An example is given here:

    - future = create.selectFrom(BOOK).where(... complex predicates ...).fetchLater(); // This example actively waits for the result to be done @@ -6140,27 +6033,25 @@ while (!future.isDone()) { } // The result should be ready, now -Result result = future.get();]]> +Result result = future.get();]]>

    Note, that instead of letting jOOQ spawn a new thread, you can also provide jOOQ with your own :

    - future = create.selectFrom(BOOK).where(... complex predicates ...).fetchLater(service);]]> - -
    +FutureResult future = create.selectFrom(BOOK).where(... complex predicates ...).fetchLater(service);]]>
    ResultSet fetching - +

    When interacting with legacy applications, you may prefer to have jOOQ return a , rather than jOOQ's own types. This can be done simply, in two ways:

    - +rs2.close();]]>

    Transform jOOQ's Result into a JDBC ResultSet

    Instead of operating on a JDBC ResultSet holding an open resource from your database, you can also let jOOQ's wrap itself in a . The advantage of this is that the so-created ResultSet has no open connection to the database. It is a completely in-memory ResultSet:

    - result = create.selectFrom(BOOK).fetch(); -ResultSet rs = result.intoResultSet();]]> +ResultSet rs = result.intoResultSet();]]>

    The inverse: Fetch data from a legacy ResultSet using jOOQ

    The inverse of the above is possible too. Maybe, a legacy part of your application produces JDBC , and you want to turn them into a :

    - result = create.fetch(rs); // As a Cursor -Cursor cursor = create.fetchLazy(rs);]]> - -
    +Cursor cursor = create.fetchLazy(rs);]]>
    Data type conversion - +

    Apart from a few extra features (see the manual's section about and ), jOOQ only supports basic types as supported by the JDBC API. In your application, you may choose to transform these data types into your own ones, without writing too much boiler-plate code. This can be done using jOOQ's types. A converter essentially allows for two-way conversion between two Java data types <T> and <U>. By convention, the <T> type corresponds to the type in your database whereas the >U> type corresponds to your own user type. The Converter API is given here:

    - extends Serializable { + extends Serializable { /** * Convert a database object to a user object @@ -6224,7 +6113,7 @@ Cursor cursor = create.fetchLazy(rs);]]> * The user type */ Class toType(); -}]]> +}]]>

    Such a converter can be used in many parts of the jOOQ API. Some examples have been illustrated in the manual's section about . @@ -6235,7 +6124,7 @@ Cursor cursor = create.fetchLazy(rs);]]> Here is a some more elaborate example involving a Converter for :

    - { @Override @@ -6264,14 +6153,14 @@ public class CalendarConverter implements Converter dates1 = create.selectFrom(BOOK).fetch().getValues(BOOK.PUBLISHING_DATE, new CalendarConverter()); List dates2 = create.selectFrom(BOOK).fetch(BOOK.PUBLISHING_DATE, new CalendarConverter()); -]]> +]]>

    Enum Converters

    jOOQ ships with a built-in default , that you can use to map VARCHAR values to enum literals or NUMBER values to enum ordinals (both modes are supported). Let's say, you want to map a YES / NO / MAYBE column to a custom Enum:

    - +}]]>

    Using Converters in generated source code

    jOOQ also allows for generated source code to reference your own custom converters, in order to permanently replace a <T> type by your own, custom <U> type. See the manual's section about for details.

    -
    +
    Static statements vs. Prepared Statements - +

    With JDBC, you have full control over your SQL statements. You can decide yourself, if you want to execute a static without bind values, or a with (or without) bind values. But you have to decide early, which way to go. And you'll have to prevent SQL injection and syntax errors manually, when inlining your bind variables.

    @@ -6311,7 +6200,7 @@ for (BookRecord book : create.selectFrom(BOOK).fetch()) { With jOOQ, this is easier. As a matter of fact, it is plain simple. With jOOQ, you can just set a flag in your , and all queries produced by that factory will be executed as static statements, with all bind values inlined. An example is given here:

    - + - - +

    Reasons for choosing one or the other

    @@ -6345,12 +6233,12 @@ inlined.select(val(1)).where(val(1).equal(1)).fetch();]]>

    Note that you don't have to inline all your bind values at once. If you know that a bind value is not really a variable and should be inlined explicitly, you can do so by using , as documented in the manual's section about

    -
    +
    Reusing a Query's PreparedStatement - +

    As previously discussed in the chapter about , reusing PreparedStatements is handled a bit differently in jOOQ from how it is handled in JDBC

    @@ -6360,7 +6248,7 @@ inlined.select(val(1)).where(val(1).equal(1)).fetch();]]> With JDBC, you can easily reuse a by not closing it between subsequent executions. An example is given here:

    - +}]]>

    The above technique can be quite useful when you want to reuse expensive database resources. This can be the case when your statement is executed very frequently and your database would take non-negligible time to soft-parse the prepared statement and generate a new statement / cursor resource. @@ -6387,7 +6275,7 @@ finally { This is also modeled in jOOQ. However, the difference to JDBC is that closing a statement is the default action, whereas keeping it open has to be configured explicitly. This is better than JDBC, because the default action should be the one that is used most often. Keeping open statements is rarely done in average applications. Here's an example of how to keep open PreparedStatements with jOOQ:

    - query = create.selectOne().keepStatement(true); // Execute the query twice, against the same underlying PreparedStatement: @@ -6399,17 +6287,17 @@ try { // ... but now, you must not forget to close the query finally { query.close(); -}]]> +}]]>

    The above example shows how a query can be executed twice against the same underlying PreparedStatement. Unlike in other execution scenarios, you must not forget to close this query now

    -
    +
    Using JDBC batch operations - +

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

    @@ -6422,7 +6310,7 @@ finally {

    In code, this looks like the following snippet:

    - +int[] result = stmt.executeBatch();]]>

    This will also be supported by jOOQ

    @@ -6458,7 +6346,7 @@ int[] result = stmt.executeBatch();]]> jOOQ supports executing queries in batch mode as follows:

    - -
    + .execute();]]>
    Sequence execution - +

    Most databases support sequences of some sort, to provide you with unique values to be used for primary keys and other enumerations. If you're using jOOQ's , it will generate a sequence object per sequence for you. There are two ways of using such a sequence object:

    @@ -6490,34 +6377,34 @@ create.batch(create.insertInto(AUTHOR, ID, NAME).values("?", "?")) Instead of actually phrasing a select statement, you can also use the convenience methods:

    - +BigInteger currID = create.currval(S_AUTHOR_ID);]]>

    Inlining sequence references in SQL

    You can inline sequence references in jOOQ SQL statements. The following are examples of how to do that:

    - +]]>

    For more info about inlining sequence references in SQL statements, please refer to the manual's section about .

    -
    +
    Stored procedures and functions - +

    Many RDBMS support the concept of "routines", usually calling them procedures and/or functions. These concepts have been around in programming languages for a while, also outside of databases. Famous languages distinguishing procedures from functions are:

    @@ -6566,14 +6453,14 @@ create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) If you're using jOOQ's , it will generate objects for you. Let's consider the following example:

    - +

    The generated artefacts can then be used as follows:

    - +assertEquals(new BigDecimal("2"), procedure.getId();]]>

    But you can also call the procedure using a generated convenience method in a global Routines class:

    - +assertEquals(new BigDecimal("2"), procedure.getId();]]>

    For more details about for procedures, see the manual's section about . @@ -6605,31 +6492,30 @@ assertEquals(new BigDecimal("2"), procedure.getId();]]> Unlike procedures, functions can be inlined in SQL statements to generate or , if you're using . Assume you have a function like this:

    - +

    The generated artefacts can then be used as follows:

    - + - - +

    For more info about inlining stored function references in SQL statements, please refer to the manual's section about .

    -
    +
    Oracle Packages - +

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

    @@ -6643,17 +6529,17 @@ create.select(authorExists("Paulo")).fetchOne(0, boolean.class);]]>

    For more details about for procedures and packages see the manual's section about .

    -
    +
    Oracle member procedures - +

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

    - MEMBER FUNCTION counBOOKs RETURN NUMBER ) --- The type body is omitted for the example]]> +-- The type body is omitted for the example]]>

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

    - +assertNotNull(author.getLastName());]]>

    For more details about for UDTs see the manual's section about .

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

    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 the ). You can export any Result<Record> into the formats discussed in the subsequent chapters of the manual

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

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

    - + @@ -6725,86 +6609,79 @@ String xml = create.selectFrom(BOOK).fetch().formatXML(); Animal Farm -]]> +]]>

    The same result as an can be obtained using the Result.intoXML() method:

    -// Fetch books and format them as XML -Document xml = create.selectFrom(BOOK).fetch().intoXML(); +// Fetch books and format them as XML +Document xml = create.selectFrom(BOOK).fetch().intoXML();

    See the XSD schema definition here, for a formal definition of the XML export format:
    http://www.jooq.org/xsd/jooq-export-1.6.2.xsd

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

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

    -ID,AUTHOR_ID,TITLE +ID,AUTHOR_ID,TITLE 1,1,1984 -2,1,Animal Farm +2,1,Animal Farm

    In addition to the standard behaviour, you can also specify a separator character, as well as a special string to represent NULL values (which cannot be represented in standard CSV):

    -// Use ";" as the separator character +// Use ";" as the separator character String csv = create.selectFrom(BOOK).fetch().formatCSV(';'); // Specify "{null}" as a representation for NULL values -String csv = create.selectFrom(BOOK).fetch().formatCSV(';', "{null}"); - -
    +String csv = create.selectFrom(BOOK).fetch().formatCSV(';', "{null}");
    Exporting JSON - - -// Fetch books and format them as JSON -String json = create.selectFrom(BOOK).fetch().formatJSON(); + // Fetch books and format them as JSON +String json = create.selectFrom(BOOK).fetch().formatJSON();

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

    -{"fields":[{"name":"field-1","type":"type-1"}, +{"fields":[{"name":"field-1","type":"type-1"}, {"name":"field-2","type":"type-2"}, ..., {"name":"field-n","type":"type-n"}], "records":[[value-1-1,value-1-2,...,value-1-n], - [value-2-1,value-2-2,...,value-2-n]]} + [value-2-1,value-2-2,...,value-2-n]]}

    Note: This format has changed in jOOQ 2.6.0

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

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

    - + ID @@ -6824,76 +6701,72 @@ String html = create.selectFrom(BOOK).fetch().formatHTML(); Animal Farm -]]> - -
    +]]>
    Exporting Text - - -// Fetch books and format them as text -String text = create.selectFrom(BOOK).fetch().format(); + // Fetch books and format them as text +String text = create.selectFrom(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| -+---+---------+-----------+ ++---+---------+-----------+

    A simple text representation can also be obtained by calling toString() on a Result object. See also the manual's section about

    -
    +
    Importing data - +

    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 the formats described in the subsequent sections of this manual.

    -
    +
    Importing CSV - +

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

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

    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, dialect); +Factory create = new Factory(connection, dialect); // Load data into the AUTHOR table from an input stream // holding the CSV data. create.loadInto(AUTHOR) .loadCSV(inputstream) .fields(ID, AUTHOR_ID, TITLE) - .execute(); + .execute();

    Here are various other examples:

    -// Ignore the AUTHOR_ID column from the CSV file when inserting +// Ignore the AUTHOR_ID column from the CSV file when inserting create.loadInto(AUTHOR) .loadCSV(inputstream) .fields(ID, null, TITLE) @@ -6934,13 +6807,13 @@ create.loadInto(AUTHOR) .loadCSV(inputstream) .fields(ID, null, TITLE) - .execute(); + .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(); + loader = /* .. */ .execute(); // The number of processed rows int processed = loader.processed(); @@ -6963,23 +6836,21 @@ int rowIndex = error.rowIndex(); String[] row = error.row(); // The query that caused the error -Query query = error.query();]]> - -
    +Query query = error.query();]]>
    Importing XML - +

    This is not yet supported

    -
    +
    CRUD with UpdatableRecords - +

    Your database application probably consists of 50% - 80% CRUD, whereas only the remaining 20% - 50% of querying is actual querying. Most often, you will operate on records of tables without using any advanced relational concepts. This is called CRUD for

    @@ -6998,13 +6869,13 @@ Query query = error.query();]]> In normalised databases, every table has a primary key by which a tuple/record within that table can be uniquely identified. In simple cases, this is a (possibly auto-generated) number called ID. But in many cases, primary keys include several non-numeric columns. An important feature of such keys is the fact that in most databases, they are enforced using an index that allows for very fast random access to the table. A typical way to access / modify / delete a book is this:

    - +DELETE FROM BOOK WHERE ID = 5;]]>

    Normalised databases assume that a primary key is unique "forever", i.e. that a key, once inserted into a table, will never be changed or re-inserted after deletion. In order to use jOOQ's operations correctly, you should design your database accordingly. @@ -7022,24 +6893,24 @@ DELETE FROM BOOK WHERE ID = 5;]]>

    For simplicity, the term "primary key" will be used in the sense of such a "main unique key" in this manual.

    -
    +
    Simple CRUD - +

    If you're using jOOQ's , it will generate implementations for every table that has a primary key. When such a record form the database, these records are "attached" to the that created them. This means that they hold an internal reference to the same database connection that was used to fetch them. This connection is used internally by any of the following methods of the UpdatableRecord:

    - +int delete() throws DataAccessException;]]>

    See the manual's section about for some more insight on "attached" objects. @@ -7050,7 +6921,7 @@ int delete() throws DataAccessException;]]> Storing a record will perform an or an . In general, new records are always inserted, whereas records loaded from the database are always updated. This is best visualised in code:

    - +book2.store();]]>

    Some remarks about storing: @@ -7086,11 +6957,11 @@ book2.store();]]> Deleting a record will remove it from the database. Here's how you delete records:

    - +book.delete();]]>

    Refreshing

    @@ -7100,53 +6971,52 @@ book.delete();]]> In order to perform a refresh, use the following Java code:

    - +book.refresh();]]>

    CRUD and SELECT statements

    CRUD operations can be combined with regular querying, if you select records from single database tables, as explained in the manual's section about . For this, you will need to use the selectFrom() method from the :

    - -
    +}]]>
    IDENTITY values - +

    Many databases support the concept of IDENTITY values, or key values. This is reflected by JDBC's method. jOOQ abstracts using this method as many databases and JDBC drivers behave differently with respect to generated keys. Let's assume the following SQL Server BOOK table:

    - +)]]>

    If you're using jOOQ's , the above table will generate a with an IDENTITY column. This information is used by jOOQ internally, to update IDs after calling :

    - +System.out.println(book.getId());]]>

    Database compatibility

    @@ -7155,8 +7025,8 @@ System.out.println(book.getId());]]>

    These SQL dialects implement the standard very neatly.

    - +

    H2, MySQL, Postgres, SQL Server, Sybase ASE, Sybase SQL Anywhere @@ -7164,7 +7034,7 @@ id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1)]]>

    These SQL dialects implement identites, but the DDL syntax doesn’t follow the standard

    - +id INTEGER NOT NULL IDENTITY]]>

    Oracle @@ -7188,7 +7058,7 @@ id INTEGER NOT NULL IDENTITY]]>

    Oracle does not know any identity columns at all. Instead, you will have to use a trigger and update the ID column yourself, using a custom sequence. Something along these lines:

    - +END my_trigger;]]>

    Note, that this approach can be employed in most databases supporting sequences and triggers! It is a lot more flexible than standard identities

    -
    +
    Non-updatable records - +

    Tables without UNIQUE keys are considered non-updatable by jOOQ, as jOOQ has no way of uniquely identifying such a record within the database. If you're using jOOQ's , such tables will generate classes, instead of classes. When you fetch from such a table, the returned records will not allow for calling any of the methods.

    @@ -7273,12 +7141,12 @@ List books = coAuthor.fetchBookListByCoAuthorId();]]>

    Note, that some databases use internal rowid or object-id values to identify such records. jOOQ does not support these vendor-specific record meta-data.

    -
    +
    Optimistic locking - +

    jOOQ allows you to perform operations using optimistic locking. You can immediately take advantage of this feature by activating the relevant . Without any further knowledge of the underlying data semantics, this will have the following impact on store() and delete() methods:

    @@ -7293,7 +7161,7 @@ List books = coAuthor.fetchBookListByCoAuthorId();]]> The above changes to jOOQ's behaviour are transparent to the API, the only thing you need to do for it to be activated is to set the Settings flag. Here is an example illustrating optimistic locking:

    - +book2.store();]]>

    Optimised optimistic locking using TIMESTAMP fields

    If you're using jOOQ's , you can take indicate TIMESTAMP or UPDATE COUNTER fields for every generated table in the . Let's say we have this table:

    - +)]]>

    The MODIFIED column will contain a timestamp indicating the last modification timestamp for any book in the BOOK table. If you're using jOOQ and it's , jOOQ will then generate this TIMESTAMP value for you, automatically. However, instead of running an additional statement prior to an UPDATE or DELETE statement, jOOQ adds a WHERE-clause to the UPDATE or DELETE statement, checking for TIMESTAMP's integrity. This can be best illustrated with an example:

    - +book2.store();]]>

    As before, without the added TIMESTAMP column, optimistic locking is transparent to the API. @@ -7356,17 +7224,17 @@ book2.store();]]>

    Note, for explicit pessimistic locking, please consider the manual's section about the . For more details about how to configure TIMESTAMP or VERSION fields, consider the manual's section about .

    -
    +
    Batch execution - +

    When inserting, updating, deleting a lot of records, you may wish to profit from JDBC batch operations, which can be performed by jOOQ. These are available through jOOQ's as shown in the following example:

    - books = create.fetch(BOOK); // Modify the above books, and add some new ones: @@ -7374,24 +7242,24 @@ modify(books); addMore(books); // Batch-update and/or insert all of the above books -create.batchStore(books);]]> +create.batchStore(books);]]>

    Internally, jOOQ will render all the required SQL statements and execute them as a regular .

    -
    +
    DAOs - +

    If you're using jOOQ's , you can configure it to generate and DAOs for you. jOOQ then generates one DAO per , i.e. per table with a single-column primary key. Generated DAOs implement a common jOOQ type called . This type contains the following methods:

    - corresponds to the DAO's related table + corresponds to the DAO's related table //

    corresponds to the DAO's related generated POJO type // corresponds to the DAO's related table's primary key type. // Note that multi-column primary keys are not yet supported by DAOs @@ -7427,13 +7295,13 @@ public interface DAO, P, T> { // These methods provide DAO meta-information Table getTable(); Class

    getType(); -}]]> +}]]>

    Besides these base methods, generated DAO classes implement various useful fetch methods. An incomplete example is given here, for the BOOK table:

    - { // Columns with primary / unique keys produce fetchOne() methods @@ -7442,12 +7310,12 @@ public class BookDao extends DAOImpl { // Other columns produce fetch() methods, returning several records public List fetchByAuthorId(Integer... values) { ... } public List fetchByTitle(String... values) { ... } -}]]> +}]]>

    Note that you can further subtype those pre-generated DAO classes, to add more useful DAO methods to them. Using such a DAO is simple:

    - - -
    +bookDao.delete(book);]]>
    Exception handling - +

    Checked vs. unchecked exceptions

    This is an eternal and religious debate. Pros and cons have been discussed time and again, and it still is a matter of taste, today. In this case, jOOQ clearly takes a side. jOOQ's exception strategy is simple: @@ -7502,12 +7368,12 @@ bookDao.delete(book);]]>

    The following section about documents means of overriding jOOQ's exception handling, if you wish to deal separately with some types of constraint violations, or if you raise business errors from your database, etc.

    -
    +
    ExecuteListeners - +

    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, triggers, etc. Advanced ExecuteListeners can also provide custom implementations of Connection, PreparedStatement and ResultSet to jOOQ in apropriate methods.

    @@ -7518,7 +7384,7 @@ bookDao.delete(book);]]> Here is a sample implementation of an ExecuteListener, that is simply counting the number of queries per type that are being executed using jOOQ:

    - +}]]>

    Now, configure jOOQ's runtime to load your listener

    - + 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 - 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 +15:16:52,983 INFO - OTHER : 30 executions

    Please read the for more details @@ -7581,7 +7447,7 @@ for (ExecuteType type : ExecuteType.values()) { The following depicts an example of a custom ExecuteListener, which pretty-prints all queries being executed by jOOQ to stdout:

    - +}]]>

    See also the manual's sections about and the for more sample implementations of actual ExecuteListeners.

    -
    +
    Logging - +

    jOOQ logs all SQL queries and fetched result sets to its internal DEBUG logger, which is implemented as an . By default, execute logging is activated in the . In order to see any DEBUG log output, put either log4j or slf4j on jOOQ's classpath along with their respective configuration. A sample log4j configuration can be seen here:

    - + @@ -7643,20 +7509,20 @@ public class PrettyPrinter extends DefaultExecuteListener { -]]> +]]>

    With the above configuration, let's fetch some data with jOOQ

    - +

    The above query may result in the following log output:

    - with bind values : select "BOOK"."ID", "BOOK"."TITLE" from "BOOK" order by "BOOK"."ID" asc, limit 2 offset 1 Query executed : Total: 1.439ms Fetched result : +----+------------+ @@ -7666,7 +7532,7 @@ Fetched result : +----+------------+ : | 3|O Alquimista| : +----+------------+ Finishing : Total: 4.814ms, +3.375ms -]]> +]]>

    Essentially, jOOQ will log @@ -7682,12 +7548,12 @@ Finishing : Total: 4.814ms, +3.375ms

    If you wish to use your own logger (e.g. avoiding printing out sensitive data), you can deactivate jOOQ's logger using and implement your own .

    -
    +
    Performance considerations - +

    Many users may have switched from higher-level abstractions such as Hibernate to jOOQ, because of Hibernate's hard-to-manage performance, when it comes to large database schemas and complex second-level caching strategies. jOOQ is not a lightweight database abstraction framework, and it comes with its own overhead. Please be sure to consider the following points:

    @@ -7702,14 +7568,14 @@ Finishing : Total: 4.814ms, +3.375ms

    Don't be put off by the above paragraphs. You should optimise wisely, i.e. only in places where you really need very high throughput to your database. jOOQ's overhead compared to plain JDBC is typically less than 1ms per query.

    -
    +
    Code generation - +

    While optional, source code generation is one of jOOQ's main assets if you wish to increase developer productivity. jOOQ's code generator takes your database schema and reverse-engineers it into a set of Java classes modelling , , , , , , user-defined types and many more.

    @@ -7723,12 +7589,12 @@ Finishing : Total: 4.814ms, +3.375ms

    The following chapters will show how to configure the code generator and how to generate various artefacts.

    -
    +
    Configuration and setup of the generator - +

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

    @@ -7755,7 +7621,7 @@ Finishing : Total: 4.814ms, +3.375ms You need to tell jOOQ some things about your database connection. Here's an example of how to do it for an Oracle database

    - + @@ -7830,7 +7696,7 @@ Finishing : Total: 4.814ms, +3.375ms [/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 for a formal specification at:
    @@ -7842,7 +7708,7 @@ Finishing : Total: 4.814ms, +3.375ms Code generation works by calling this class with the above property file as argument.

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

    Be sure that these elements are located on the classpath: @@ -7905,7 +7771,7 @@ Finishing : Total: 4.814ms, +3.375ms 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:

    - + @@ -7928,26 +7794,26 @@ Finishing : Total: 4.814ms, +3.375ms generatordatabaseinputschema="test" generatortargetpackage="org.jooq.test.generatedclasses" generatortargetdirectory="${basedir}/src"/> -]]> +]]>

    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 @@ -7999,7 +7865,7 @@ Finishing : Total: 4.814ms, +3.375ms -]]> +]]>

    See the full example of a pom.xml including the jOOQ-codegen artefact here:
    @@ -8012,7 +7878,7 @@ Finishing : Total: 4.814ms, +3.375ms 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 +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 @@ -8022,17 +7888,17 @@ Finishing : Total: 4.814ms, +3.375ms

    Be sure, both jooq-{jooq-version}.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.

    -
    +
    Advanced generator configuration - +

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

    - + @@ -8044,13 +7910,13 @@ Finishing : Total: 4.814ms, +3.375ms org.jooq.util.DefaultGeneratorStrategy -]]> +]]>

    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:

    - +}]]>

    jooq-meta configuration

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

    - + ... -]]> +]]>

    Check out the some of the manual's "advanced" sections to find out more about the advanced configuration parameters. @@ -8229,7 +8095,7 @@ public class AsInDatabaseStrategy extends DefaultGeneratorStrategy { Also, you can add some optional advanced configuration parameters for the generator:

    - + false -]]> -
    +]]>
    Generated global artefacts - +

    For increased convenience at the use-site, jOOQ generates "global" artefacts at the code generation root location, referencing tables, routines, sequences, etc. In detail, these global artefacts include the following:

    @@ -8312,7 +8177,7 @@ public class AsInDatabaseStrategy extends DefaultGeneratorStrategy { When referencing global artefacts from your client application, you would typically static import them as such:

    - -
    + .values(com.example.generated.Sequences.MY_SEQUENCE.nextval(), com.example.generated.Routines.myFunction())]]>
    Generated tables - +

    Every table in your database will generate a implementation that looks like this:

    - { + { // The singleton instance public static final Book BOOK = new Book(); @@ -8351,7 +8215,7 @@ create.insertInto(com.example.generated.Tables.MY_TABLE) } // [...] -}]]> +}]]>

    Flags influencing generated tables

    @@ -8371,17 +8235,17 @@ create.insertInto(com.example.generated.Tables.MY_TABLE)

    Table generation cannot be deactivated

    -
    +
    Generated records - +

    Every table in your database will generate a implementation that looks like this:

    - @@ -8422,7 +8286,7 @@ implements IBook { } // [...] -}]]> +}]]>

    Flags influencing generated records

    @@ -8442,17 +8306,17 @@ implements IBook {

    Record generation can be deactivated using the records flag

    -
    +
    Generated POJOs - +

    Every table in your database will generate a POJO implementation that looks like this:

    - +}]]>

    Flags influencing generated POJOs

    @@ -8505,24 +8369,24 @@ public class Book implements java.io.Serializable

    POJO generation can be activated using the pojos flag

    -
    +
    Generated Interfaces - +

    Every table in your database will generate an interface that looks like this:

    - +}]]>

    Flags influencing generated interfaces

    @@ -8537,18 +8401,18 @@ public class Book implements java.io.Serializable

    POJO generation can be activated using the interfaces flag

    -
    +
    Generated DAOs - +

    Generated DAOs

    Every table in your database will generate a implementation that looks like this:

    - { + { // Generated constructors public BookDao() { @@ -8573,43 +8437,43 @@ public class Book implements java.io.Serializable } // [...] -}]]> +}]]>

    Flags controlling DAO generation

    DAO generation can be activated using the daos flag

    -
    +
    Generated sequences - +

    Every sequence in your database will generate a implementation that looks like this:

    - S_AUTHOR_ID = new SequenceImpl("S_AUTHOR_ID", TEST, SQLDataType.INTEGER); -}]]> +}]]>

    Flags controlling sequence generation

    Sequence generation cannot be deactivated

    -
    +
    Generated procedures - +

    Every procedure or function (routine) in your database will generate a implementation that looks like this:

    - { + { // All IN, IN OUT, OUT parameters and function return values generate a static member public static final Parameter AUTHOR_NAME = createParameter("AUTHOR_NAME", SQLDataType.VARCHAR); @@ -8634,7 +8498,7 @@ public class Book implements java.io.Serializable } // [...] -}]]> +}]]>

    Package and member procedures or functions

    @@ -8645,17 +8509,17 @@ public class Book implements java.io.Serializable

    Routine generation cannot be deactivated

    -
    +
    Generated UDTs - +

    Every UDT in your database will generate a implementation that looks like this:

    - { + { // The singleton UDT instance public static final UAddressType U_ADDRESS_TYPE = new UAddressType(); @@ -8669,13 +8533,13 @@ public class Book implements java.io.Serializable createField("COUNTRY", SQLDataType.VARCHAR, U_ADDRESS_TYPE); // [...] -}]]> +}]]>

    Besides the implementation, a implementation is also generated

    - { + { // Every attribute generates a getter and a setter @@ -8687,18 +8551,18 @@ public class Book implements java.io.Serializable public String getCountry() {...} // [...] -}]]> +}]]>

    Flags controlling UDT generation

    UDT generation cannot be deactivated

    -
    +
    Master data and enumeration tables - +

    NOTE: This feature is deprecated in jOOQ 2.5.0 and will be removed as of jOOQ 3.0

    @@ -8711,7 +8575,7 @@ public class Book implements java.io.Serializable As previously discussed, you can configure master data tables as follows:

    - + @@ -8727,13 +8591,13 @@ public class Book implements java.io.Serializable [ ... ... ] - ]]> + ]]>

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

    - { + { /** * English @@ -8761,7 +8625,7 @@ public class Book implements java.io.Serializable 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. @@ -8781,39 +8645,39 @@ public class Book implements java.io.Serializable 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 BookRecord directly:

    - { + { // [...] public Language getLanguageId() { // [...] public void setLanguageId(Language 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 - +

    When using a custom type in jOOQ, you need to let jOOQ know about its associated . Ad-hoc usages of such converters has been discussed in the chapter about . 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_

    - + @@ -8836,41 +8700,39 @@ public class Book implements java.io.Serializable .*\.DATE_OF_.* -]]> +]]>

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

    - { + { // [...] public final TableField DATE_OF_BIRTH = // [...] // [...] -}]]> +}]]>

    This means that the bound type 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(AUTHOR) .where(AUTHOR.DATE_OF_BIRTH.greaterThan(new GregorianCalendar(1980, 0, 1))) - .fetch(AUTHOR.DATE_OF_BIRTH);]]> - -
    + .fetch(AUTHOR.DATE_OF_BIRTH);]]>
    Mapping generated schemata and tables - +

    We've seen previously in the chapter about , that schemata and tables can be mapped at runtime to other names. But 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 @@ -8878,25 +8740,23 @@ create.selectFrom(AUTHOR) PROD -]]> - -
    +]]>
    Tools - +

    These chapters hold some information about tools to be used with jOOQ

    -
    +
    jOOQ Console - +

    The 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:

    @@ -8936,26 +8796,26 @@ create.selectFrom(AUTHOR) 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:

    - +Factory factory = new Factory(connection, dialect, 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: @@ -9016,36 +8876,36 @@ catch (Exception ignore) {} 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 +// Create a new RemoteDebuggerServer in your application that listens to // incoming connections on a given port -SERVER = new RemoteDebuggerServer(DEBUGGER_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] +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.

    -
    +
    Reference - +

    These chapters hold some general jOOQ reference information

    -
    +
    Supported RDBMS - +

    A list of supported databases

    Every RDMBS out there has its own little specialties. jOOQ considers those specialties as much as possible, while trying to standardise the behaviour in jOOQ. In order to increase the quality of jOOQ, some 70 unit tests are run for syntax and variable binding verification, as well as some 180 integration tests with an overall of around 1200 queries for any of these databases: @@ -9104,12 +8964,12 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);

    This section will soon contain a feature matrix, documenting what feature is available for which database.

    -
    +
    Data types - +

    There is always a small mismatch between SQL data types and Java data types. This is for two reasons:

    @@ -9120,21 +8980,21 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);

    This chapter should document the most important notes about SQL, JDBC and jOOQ data types.

    -
    +
    BLOBs and CLOBs - +

    jOOQ currently doesn't explicitly support JDBC BLOB and CLOB data types. If you use any of these data types in your database, jOOQ will map them to byte[] and String instead. In simple cases (small data), this simplification is sufficient. In more sophisticated cases, you may have to bypass jOOQ, in order to deal with these data types and their respective resources. True support for LOBs is on the roadmap, though.

    -
    +
    Unsigned integer types - +

    Some databases explicitly support unsigned integer data types. In most normal JDBC-based applications, they would just be mapped to their signed counterparts letting bit-wise shifting and tweaking to the user. jOOQ ships with a set of unsigned implementations modelling the following types:

    @@ -9153,12 +9013,12 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);
  • UInteger wraps
  • ULong wraps
  • -
    +
    INTERVAL data types - +

    jOOQ fills a gap opened by JDBC, which neglects an important SQL data type as defined by the SQL standards: INTERVAL types. SQL knows two different types of intervals:

    @@ -9183,51 +9043,51 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);
  • INTERVAL * or / NUMERIC => INTERVAL
  • NUMERIC * INTERVAL => INTERVAL
  • -
    +
    XML data types - +

    XML data types are currently not supported

    -
    +
    Geospacial data types - +

    Geospacial data types

    Geospacial data types are currently not supported

    -
    +
    CURSOR data types - +

    Some databases support cursors returned from stored procedures. They are mapped to the following jOOQ data type:

    -> cursor;]]> +> cursor;]]>

    In fact, such a cursor will be fetched immediately by jOOQ and wrapped in an object.

    -
    +
    ARRAY and TABLE data types - +

    The SQL standard specifies ARRAY data types, that can be mapped to Java arrays as such:

    - intArray;]]> + intArray;]]>

    The above array type is supported by these SQL dialects: @@ -9242,23 +9102,23 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);

    Oracle has strongly-typed arrays and table types (as opposed to the previously seen anonymously typed arrays). These arrays are wrapped by types.

    -
    +
    jOOQ's BNF pseudo-notation - +

    This chapter will soon contain an overview over jOOQ's API using a pseudo BNF notation.

    -
    +
    Credits - +

    jOOQ lives in a very challenging ecosystem. The Java to SQL interface is still one of the most important system interfaces. Yet there are still a lot of open questions, best practices and no "true" standard has been established. This situation gave way to a lot of tools, APIs, utilities which essentially tackle the same problem domain as jOOQ. jOOQ has gotten great inspiration from pre-existing tools and this section should give them some credit. Here is a list of inspirational tools in alphabetical order:

    @@ -9271,7 +9131,7 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);
  • QueryDSL: A "LINQ-port" to Java. It has a similar fluent API, a similar code-generation facility, yet quite a different purpose. While jOOQ is all about SQL, QueryDSL (like LINQ) is mostly about querying.
  • Spring Data: Spring's JdbcTemplate knows RowMappers, which are reflected by jOOQ's or
  • -
    +
    diff --git a/jOOQ-website/src/main/resources/manual-2.7.xml b/jOOQ-website/src/main/resources/manual-2.7.xml index e709e7159b..b33940e4e2 100644 --- a/jOOQ-website/src/main/resources/manual-2.7.xml +++ b/jOOQ-website/src/main/resources/manual-2.7.xml @@ -37,7 +37,7 @@
    The jOOQ User Manual. Multiple Pages - +

    # Overview

    This manual is divided into six main sections:

    @@ -88,12 +88,12 @@

    -
    +
    Preface - +

    jOOQ's reason of being - compared to JPA

    Java and SQL have come a long way. SQL is an "ancient", yet established and well-understood technology. Java is a legacy too, although its platform JVM allows for many new and contemporary languages built on top of it. Yet, after all these years, libraries dealing with the interface between SQL and Java have come and gone, leaving JPA to be a standard that is accepted only with doubts, short of any surviving options. @@ -126,18 +126,18 @@

    SQL was never meant to be abstracted. To be confined in the narrow boundaries of heavy mappers, hiding the beauty and simplicity of relational data. SQL was never meant to be object-oriented. SQL was never meant to be anything other than... SQL!

    -
    +
    Getting started with jOOQ - +

    These chapters contain a quick overview of how to get started with this manual and with jOOQ. While the subsequent chapters contain a lot of reference information, this chapter here just wraps up the essentials.

    -
    +
    How to read this manual - +

    This section helps you correctly interpret this manual in the context of jOOQ.

    @@ -279,28 +279,21 @@ and Maintenance Agreement for more details: http://www.jooq.org/eula The following are code blocks:

    - - - - - -]]> - - + +]]>

    These are useful to provide examples in code. Often, with jOOQ, it is even more useful to compare SQL code with its corresponding Java/jOOQ code. When this is done, the blocks are aligned side-by-side, with SQL usually being on the left, and Java usually being on the right:

    - + - - +

    Code block contents

    @@ -308,13 +301,11 @@ create.select()]]>

    - - - +Factory create = new Factory(connection, SQLDialect.ORACLE);]]>

    Settings

    @@ -335,16 +326,16 @@ Factory create = new Factory(connection, SQLDialect.ORACLE);]]>

    See the manual's section about to learn more about the sample database.

    -
    +
    The sample database used in this manual - +

    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 language ( +CREATE TABLE language ( id NUMBER(7) NOT NULL PRIMARY KEY, cd CHAR(2) NOT NULL, description VARCHAR2(50) @@ -382,16 +373,16 @@ CREATE TABLE book_to_book_store ( PRIMARY KEY(name, book_id), CONSTRAINT fk_b2bs_book_store FOREIGN KEY (name) REFERENCES book_store (name) ON DELETE CASCADE, CONSTRAINT fk_b2bs_book FOREIGN KEY (book_id) REFERENCES 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

    -
    +
    Different use cases for jOOQ - +

    jOOQ has originally been created as a library for complete abstraction of JDBC and all database interaction. Various best practices that are frequently encountered in pre-existing software products are applied to this library. This includes:

    @@ -420,23 +411,23 @@ CREATE TABLE book_to_book_store (

    The following sections explain about various use cases for using jOOQ in your application.

    -
    +
    jOOQ as a SQL builder - +

    This is the most simple of all use cases, allowing for construction of valid SQL for any database. In this use case, you will not use and probably not even . Instead, you'll use jOOQ to wrap strings, literals and other user-defined objects into an object-oriented, type-safe AST modelling your SQL statements. An example is given here:

    - + .getSQL();]]>

    The SQL string that you can generate as such can then be executed using JDBC directly, using Spring's JdbcTemplate, using Apache DbUtils and many other tools. @@ -448,23 +439,23 @@ String sql = create.select(fieldByName("BOOK","TITLE"), fieldByName("AUTHOR","FI

  • : This section contains a lot of information about creating SQL statements using the jOOQ API
  • : This section contains information useful in particular to those that want to supply , , etc. as plain SQL to jOOQ, rather than through generated artefacts
  • -
    +
    jOOQ as a SQL builder with code generation - +

    In addition to using jOOQ as a , you can also use jOOQ's code generation features in order to compile your SQL statements using a Java compiler against an actual database schema. This adds a lot of power and expressiveness to just simply constructing SQL using custom strings and literals, as you can be sure that all database artefacts actually exist in the database, and that their type is correct. An example is given here:

    - + .getSQL();]]>

    The SQL string that you can generate as such can then be executed using JDBC directly, using Spring's JdbcTemplate, using Apache DbUtils and many other tools. @@ -476,29 +467,29 @@ String sql = create.select(BOOK.TITLE, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)

  • : This section contains a lot of information about creating SQL statements using the jOOQ API
  • : This section contains the necessary information to run jOOQ's code generator against your developer database
  • -
    +
    jOOQ as a SQL executor - +

    Instead of any tool mentioned in the previous chapters, you can also use jOOQ directly to execute your jOOQ-generated SQL statements. This will add a lot of convenience on top of the previously discussed API for typesafe SQL construction, when you can re-use the information from generated classes to fetch records and custom data types. An example is given here:

    - result = create.select(BOOK.TITLE, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .from(BOOK) .join(AUTHOR) .on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)) .where(BOOK.PUBLISHED_IN.equal(1948)) - .fetch();]]> + .fetch();]]>

    jOOQ doesn't stop here, though! You can execute any SQL with jOOQ. In other words, you can use any other SQL building tool and run the SQL statements with jOOQ. An example is given here:

    - result = create.fetch(sql); // Or execute that SQL with JDBC, fetching the ResultSet with jOOQ: ResultSet rs = connection.createStatement().executeQuery(sql); -Result result = create.fetch(rs);]]> +Result result = create.fetch(rs);]]>

    If you wish to use jOOQ as a SQL executor with (or without) code generation, the following sections of the manual will be of interest to you: @@ -518,17 +509,17 @@ Result result = create.fetch(rs);]]>

  • : This section contains a lot of information about executing SQL statements using the jOOQ API
  • : This section contains some useful information about the various ways of fetching data with jOOQ
  • -
    +
    jOOQ for CRUD - +

    This is probably the most complete use-case for jOOQ: Use all of jOOQ's features. Apart from jOOQ's fluent API for query construction, jOOQ can also help you execute everyday CRUD operations. An example is given here:

    - +}]]>

    If you wish to use all of jOOQ's features, the following sections of the manual will be of interest to you (including all sub-sections): @@ -552,12 +543,12 @@ for (AuthorRecord author : create.fetch(AUTHOR)) {

  • : This section contains the necessary information to run jOOQ's code generator against your developer database
  • : This section contains a lot of information about executing SQL statements using the jOOQ API
  • -
    +
    jOOQ for PROs - +

    jOOQ isn't just a library that helps you and SQL against your . jOOQ ships with a lot of tools. Here are some of the most important tools shipped with jOOQ:

    @@ -571,32 +562,32 @@ for (AuthorRecord author : create.fetch(AUTHOR)) {

    If you're a power user of your favourite, feature-rich database, jOOQ will help you access all of your database's vendor-specific features, such as OLAP features, stored procedures, user-defined types, vendor-specific SQL, functions, etc. Examples are given throughout this manual.

    -
    +
    Tutorials - +

    Don't have time to read the full manual? Here are a couple of tutorials that will get you into the most essential parts of jOOQ as quick as possible.

    -
    +
    jOOQ in 7 easy steps - +

    This manual section is intended for new users, to help them get a running application with jOOQ, quickly.

    -
    +
    Step 1: Preparation - +

    If you haven't already downloaded it, download jOOQ:
    https://sourceforge.net/projects/jooq/files/Release/ @@ -605,12 +596,12 @@ for (AuthorRecord author : create.fetch(AUTHOR)) {

    Alternatively, you can create a Maven dependency:

    - + org.jooq jooq {jooq-version} -]]> +]]>

    For this example, we'll be using MySQL. If you haven't already downloaded MySQL Connector/J, download it here:
    @@ -620,17 +611,17 @@ for (AuthorRecord author : create.fetch(AUTHOR)) {

    If you don't have a MySQL instance up and running yet, get XAMPP now! XAMPP is a simple installation bundle for Apache, MySQL, PHP and Perl

    -
    +
    Step 2: Your database - +

    We're going to create a database called "guestbook" and a corresponding "posts" table. Connect to MySQL via your command line client and type the following:

    -CREATE DATABASE guestbook; +CREATE DATABASE guestbook; CREATE TABLE `posts` ( `id` bigint(20) NOT NULL, @@ -639,13 +630,12 @@ CREATE TABLE `posts` ( `title` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ); - -
    +
    Step 3: Code generation - +

    In this step, we're going to use jOOQ's command line tools to generate classes that map to the Posts table we just created. More detailed information about how to set up the jOOQ code generator can be found here:
    @@ -655,7 +645,7 @@ CREATE TABLE `posts` ( The easiest way to generate a schema is to copy the jOOQ jar files (there should be 3) and the MySQL Connector jar file to a temporary directory. Then, create a guestbook.xml that looks like this:

    - + @@ -696,7 +686,7 @@ CREATE TABLE `posts` ( C:/workspace/MySQLTest/src -]]> +]]>

    Replace the username with whatever user has the appropriate privileges to query the database meta data. You'll also want to look at the other values and replace as necessary. Here are the two interesting properties:

    @@ -711,15 +701,15 @@ CREATE TABLE `posts` ( Once you have the JAR files and guestbook.xml in your temp directory, type this (use colons instead of semi-colons on UNIX/Linux systems):

    -java -classpath jooq-{jooq-version}.jar;jooq-meta-{jooq-version}.jar;jooq-codegen-{jooq-version}.jar;mysql-connector-java-5.1.18-bin.jar;. +java -classpath jooq-{jooq-version}.jar;jooq-meta-{jooq-version}.jar;jooq-codegen-{jooq-version}.jar;mysql-connector-java-5.1.18-bin.jar;. org.jooq.util.GenerationTool /guestbook.xml - +

    Note the prefix slash before guestbook.xml. Even though it's in our working directory, we need to prepend a slash, as the configuration file is loaded from the classpath. Replace the filenames with your filenames. In this example, jOOQ {jooq-version} is being used. If everything has worked, you should see this in your console output:

    -Nov 1, 2011 7:25:06 PM org.jooq.impl.JooqLogger info +Nov 1, 2011 7:25:06 PM org.jooq.impl.JooqLogger info INFO: Initialising properties : /guestbook.xml Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info INFO: Database parameters @@ -777,19 +767,17 @@ Nov 1, 2011 7:25:08 PM org.jooq.impl.JooqLogger info INFO: Packages fetched : 0 (0 included, 0 excluded) Nov 1, 2011 7:25:08 PM org.jooq.impl.JooqLogger info INFO: GENERATION FINISHED! : Total: 791.688ms, +9.143ms - - -
    +
    Step 4: Connect to your database - +

    Let's just write a vanilla main class in the project containing the generated classes:

    - +}]]>

    This is pretty standard code for establishing a MySQL connection.

    -
    +
    Step 5: Querying - +

    Let's add a simple query:

    - result = create.select().from(POSTS).fetch();]]> + result = create.select().from(POSTS).fetch();]]>

    First get an instance of Factory so we can write a simple SELECT query. We pass an instance of the MySQL connection to Factory. Note that the factory doesn't close the connection. We'll have to do that ourselves. @@ -840,29 +828,29 @@ Result result = create.select().from(POSTS).fetch();]]>

    We then use jOOQ's DSL to return an instance of Result. We'll be using this result in the next step.

    -
    +
    Step 6: Iterating - +

    After the line where we retrieve the results, let's iterate over the results and print out the data:

    - +}]]>

    The full program should now look like this:

    - -
    +}]]>
    Step 7: Explore! - +

    jOOQ has grown to be a comprehensive SQL library. For more information, please consider the manual:
    http://www.jooq.org/manual/ @@ -941,37 +928,37 @@ public class Main { This tutorial is the courtesy of Ikai Lan. See the original source here:
    http://ikaisays.com/2011/11/01/getting-started-with-jooq-a-tutorial/

    -
    +
    Using jOOQ in modern IDEs - +

    Feel free to contribute a tutorial!

    -
    +
    Using jOOQ with Spring - +

    Feel free to contribute a tutorial!

    -
    +
    A simple web application with jOOQ - +

    Feel free to contribute a tutorial!

    -
    +
    jOOQ and Scala - +

    As any other library, jOOQ can be easily used in Scala, taking advantage of the many Scala language features such as for example:

    @@ -994,7 +981,7 @@ public class Main { A short example jOOQ application in Scala might look like this:

    - +}]]>

    For more details about jOOQ's Scala integration, please refer to the manual's section about .

    -
    +
    Dependencies - +

    jOOQ has no dependencies on any third-party libraries. This rule has some exceptions:

    @@ -1057,14 +1044,14 @@ object Test { //

    In order to build jOOQ, please download the sources from https://github.com/jOOQ/jOOQ and use Maven to build it, preferably in Eclipse.

    -
    +
    SQL building - +

    SQL is a declarative language that is hard to integrate into procedural, object-oriented, functional or any other type of programming languages. jOOQ's philosophy is to give SQL the credit it deserves and integrate SQL itself as an "internal domain specific language" directly into Java.

    @@ -1074,12 +1061,12 @@ object Test { //

    This section explains all about the various syntax elements involved with jOOQ's SQL building capabilities. For a complete overview of all syntax elements, please refer to the manual's section about

    -
    +
    The Factory class - +

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

    @@ -1100,13 +1087,13 @@ object Test { //

    With jOOQ 2.0, static factory methods have been introduced in order to make client 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.*; + import static org.jooq.impl.Factory.*;

    Note, that when working with Eclipse, you could also add the Factory to your favourites. This will allow to access functions even more fluently:

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

    The Factory as a Configuration object

    @@ -1121,20 +1108,19 @@ Factory.concat(Factory.trim(FIRST_NAME), Factory.trim(LAST_NAME));

    As a Configuration object, a Factory can construct , for later . An example is given here:

    - select = create.selectOne(); // Using the internally referenced Factory, the select statement can now be executed: -Result result = select.fetch();]]> -
    +Result result = select.fetch();]]>
    SQL Dialect - +

    While jOOQ tries to represent the SQL standard as much as possible, many features are vendor-specific to a given database and to its "SQL dialect". jOOQ models this using the enum type.

    @@ -1144,26 +1130,26 @@ Result result = select.fetch();]]>

    Some parts of the jOOQ API are officially supported only by a given subset of the supported SQL dialects. For instance, the , which is supported by the Oracle and CUBRID databases, is annotated with a annotation, as such:

    -CONNECT BY clause to the query */ @Support({ CUBRID, ORACLE }) -SelectConnectByConditionStep connectBy(Condition condition);]]> +SelectConnectByConditionStep connectBy(Condition condition);]]>

    jOOQ API methods which are not annotated with the annotation, or which are annotated with the Support annotation, but without any SQL dialects can be safely used in all SQL dialects. An example for this is the factory method:

    -... fields);]]> +SelectSelectStep select(Field... fields);]]>

    jOOQ's SQL clause simulation capabilities

    The aforementioned Support annotation does not only designate, which databases natively support a feature. It also indicates that a feature is simulated by jOOQ for some databases lacking this feature. An example of this is the , a predicate syntax defined by SQL:1999 and implemented only by H2, HSQLDB, and Postgres:

    - +

    Nevertheless, the IS DISTINCT FROM predicate is supported in all dialects, as its semantics can be expressed with an equivalent . For more details, see the manual's section about the . @@ -1183,12 +1169,12 @@ SelectSelectStep select(Field... fields);]]>

    jOOQ has a historic affinity to Oracle's SQL extensions. If something is supported in Oracle SQL, it has a high probability of making it into the jOOQ API

    -
    +
    Connection vs. DataSource - +

    Interact with JDBC Connections

    While you can use jOOQ for only, you can also run queries against a JDBC . Internally, jOOQ creates or objects from such a Connection, in order to execute statements. The normal operation mode is to provide a with a JDBC Connection, whose lifecycle you will control yourself. This means that jOOQ will not actively close connections, rollback or commit transactions. @@ -1197,12 +1183,12 @@ SelectSelectStep select(Field... fields);]]>

    If you're in a J2EE or Spring context, however, you may wish to use a instead. Currently, Connections obtained from such a DataSource will be closed after query execution by jOOQ. The semantics of such a close operation should be the returning of the connection into a connection pool, not the actual closing of the underlying physical connection. Typically, this makes sense in an environment using distributed JTA transactions. An example of using DataSources with jOOQ can be seen in the tutorial section about .

    -
    +
    Custom 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:

    @@ -1216,9 +1202,9 @@ SelectSelectStep select(Field... fields);]]>

    For example, if you want to indicate to jOOQ, that it should inline all bind variables, and execute static instead of binding its variables to , you can do so by using the following Factory:

    - +Factory create = new Factory(connection, dialect, settings);]]>

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

    @@ -1240,12 +1226,12 @@ Factory create = new Factory(connection, dialect, settings);]]> Please refer to the jOOQ runtime configuration XSD for more details:
    http://www.jooq.org/xsd/jooq-runtime-2.5.0.xsd

    -
    +
    Runtime schema and table mapping - +

    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. @@ -1265,7 +1251,7 @@ Factory create = new Factory(connection, dialect, settings);]]> 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 with. Take the following example:

    -Settings settings = new Settings() +Settings settings = new Settings() .withRenderMapping(new RenderMapping() .withSchemata( new MappedSchema().withInput("DEV") @@ -1275,13 +1261,13 @@ Factory create = new Factory(connection, dialect, settings);]]> Factory create = new Factory(connection, SQLDialect.ORACLE, settings); // Run queries with the "mapped" factory -create.selectFrom(AUTHOR).fetch(); +create.selectFrom(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.AUTHOR +SELECT * FROM MY_BOOK_WORLD.AUTHOR

    Even if AUTHOR was generated from DEV.

    @@ -1291,7 +1277,7 @@ create.selectFrom(AUTHOR).fetch(); 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):

    - + @@ -1304,13 +1290,13 @@ create.selectFrom(AUTHOR).fetch(); -]]> +]]>

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

    -Settings settings = JAXB.unmarshal(new File("jooq-runtime.xml"), Settings.class); +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 @@ -1322,40 +1308,40 @@ create.selectFrom(AUTHOR).fetch(); 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 +// Set the default schema Schema MY_BOOK_WORLD = ... create.use(MY_BOOK_WORLD); // Run queries with factory having a default schema -create.selectFrom(AUTHOR).fetch(); +create.selectFrom(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 AUTHOR +-- the schema name is omitted from all SQL constructs. +SELECT * FROM AUTHOR

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

    -Settings settings = new Settings() +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(AUTHOR).fetch(); +create.selectFrom(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.AUTHOR to something MY_BOOK_WORLD.MY_APP__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() +Settings settings = new Settings() .withRenderMapping(new RenderMapping() .withSchemata( new MappedSchema().withInput("DEV") @@ -1368,13 +1354,13 @@ create.selectFrom(AUTHOR).fetch(); Factory create = new Factory(connection, SQLDialect.ORACLE, settings); // Run queries with the "mapped" factory -create.selectFrom(AUTHOR).fetch(); +create.selectFrom(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__AUTHOR +SELECT * FROM MY_BOOK_WORLD.MY_APP__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! @@ -1384,20 +1370,20 @@ create.selectFrom(AUTHOR).fetch();

    Note that the manual's section about explains how you can hard-wire your schema mappings at code generation time

    -
    +
    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 +// A general, dialect-unspecific factory Factory create = new Factory(connection, SQLDialect.MYSQL); // A MySQL-specific factory -MySQLFactory create = new MySQLFactory(connection); +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:

    @@ -1408,23 +1394,23 @@ MySQLFactory create = new MySQLFactory(connection);

    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. By default, such a schema-specific Factory will not render the schema name.

    -
    +
    SQL Statements - +

    jOOQ currently supports 6 types of SQL statements. All of these statements are constructed from a Factory instance with an optional . If supplied with a Connection or DataSource, they can be executed. Depending on the , executed queries can return results.

    -
    +
    jOOQ's DSL and non-DSL API - +

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

    @@ -1432,22 +1418,21 @@ MySQLFactory create = new MySQLFactory(connection); Here is an example to illustrate what that means:

    - 1920 AND a.first_name = 'Paulo' - ORDER BY b.title]]> - result = + ORDER BY b.title]]> result = create.select() .from(AUTHOR.as("a")) .join(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();]]> + .fetch();]]>

    We'll see how the aliasing works later in the section about @@ -1457,16 +1442,16 @@ create.select()

    Many other frameworks have similar APIs with similar feature sets. Yet, what makes jOOQ special is its informal modelling a unified SQL dialect suitable for many vendor-specific dialects, and implementing that BNF notation as a hierarchy of interfaces in Java. This concept is extremely powerful, when with syntax completion. Not only can you code much faster, your SQL code will be compile-checked to a certain extent. An example of a DSL query equivalent to the previous one is given here:

    - result = create.select() .from(AUTHOR) .join(BOOK).on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)) - .fetch();]]> + .fetch();]]>

    Unlike other, simpler frameworks that use "fluent APIs" or "method chaining", jOOQ's BNF-based interface hierarchy will not allow bad query syntax. The following will not compile, for instance:

    - result = create.select() .join(BOOK).on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)) // ^^^^ "join" is not possible here @@ -1482,13 +1467,13 @@ Result result = create.select() Result result = create.select(rowNumber()) // ^^^^^^^^^ "over()" is missing here .from(AUTHOR) - .fetch();]]> + .fetch();]]>

    History of SQL building and incremental query building (a.k.a. the non-DSL API)

    Historically, jOOQ started out as an object-oriented SQL builder library like any other. This meant that all queries and their syntactic components were modeled as so-called , which delegate and to child components. This part of the API will be referred to as the non-DSL API, which is still maintained and used internally by jOOQ for incremental query building. An example of incremental query building is given here:

    - result = query.fetch();]]> +Result result = query.fetch();]]>

    This query is equivalent to the one shown before using the DSL syntax. In fact, internally, the DSL API constructs precisely this QueryObject. Note, that you can always access the SelectQuery object to switch between DSL and non-DSL APIs:

    - +query.addJoin(BOOK, BOOK.AUTHOR_ID.equal(AUTHOR.ID));]]>

    Mutability

    Note, that for historic reasons, the DSL API mixes mutable and immutable behaviour with respect to the internal representation of the being constructed. While creating , (such as functions) assumes immutable behaviour, creating does not. In other words, the following can be said:

    - +s2 == s3; // The internal object is always the same]]>

    Mutability may be removed in a future version of jOOQ.

    -
    +
    The SELECT statement - +

    When you don't just perform (i.e. SELECT * FROM your_table WHERE ID = ?), you're usually generating new record 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:

    - + - - +

    Details about the various clauses of this query will be provided in subsequent sections @@ -1594,14 +1578,14 @@ create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, count()) A very similar, but limited API is available, if you want to select from single physical tables in order to retrieve . 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:

    - SimpleSelectWhereStep selectFrom(Table table);]]> + SimpleSelectWhereStep selectFrom(Table 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:

    - + .fetchAny();]]>

    The simple SELECT API is limited in the way that it does not support any of these clauses: @@ -1615,41 +1599,39 @@ create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, count())

    In most parts of this manual, it is assumed that you do not use the simple SELECT API. For more information about the simple SELECT API, see the manual's section about .

    -
    +
    The SELECT clause - +

    The SELECT clause lets you project your own record types, referencing table fields, functions, arithmetic expressions, etc. The Factory provides several methods for expressing a SELECT clause:

    - + - s1 = create.select(BOOK.ID, BOOK.TITLE); Select s2 = create.select(BOOK.ID, trim(BOOK.TITLE));]]> - +

    Some commonly used projections can be easily created using convenience methods:

    - + - select1 = create.selectCount(); Select select2 = create.selectZero(); Select select2 = create.selectOne();]]> - +

    See more details about functions and expressions in the manual's section about @@ -1660,28 +1642,26 @@ Select select2 = create.selectOne();]]> The DISTINCT keyword can be included in the method name, constructing a SELECT clause

    - - - select1 = create.selectDistinct(BOOK.TITLE);]]> - -
    + + select1 = create.selectDistinct(BOOK.TITLE);]]> + +
    The FROM clause - +

    The SQL FROM clause allows for specifying any number of to select data from. The following are examples of how to form normal FROM clauses:

    - + - - +

    Read more about aliasing in the manual's section about . @@ -1692,12 +1672,11 @@ create.selectOne().from(BOOK.as("b"), AUTHOR.as("a"));]]> Apart from simple tables, you can pass any arbitrary to the jOOQ FROM clause. This may include in Oracle:

    - + - - +

    Note, in order to access the DbmsXplan package, you can use the to generate Oracle's SYS schema. @@ -1709,22 +1688,21 @@ FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(null, null, 'ALLSTATS'));]]> In many SQL dialects, FROM is a mandatory clause, in some it isn't. jOOQ allows you to omit the FROM clause, returning just one record. An example:

    - + - - +

    Read more about dual or dummy tables in the manual's section about . The following are examples of how to form normal FROM clauses:

    -
    +
    The JOIN clause - +

    jOOQ supports many different types of standard SQL JOIN operations:

    @@ -1743,7 +1721,7 @@ new Factory(SQLDialect.POSTGRES).selectOne().getSQL();]]> All of these JOIN methods can be called on types, or directly after the FROM clause for convenience. The following example joins AUTHOR and BOOK

    - result = create.select() @@ -1756,27 +1734,26 @@ Result result = create.select() .from(AUTHOR) .join(BOOK) .on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)) - .fetch();]]> + .fetch();]]>

    The two syntaxes will produce the same SQL statement. However, calling "join" on objects allows for more powerful, nested JOIN expressions (if you can handle the parentheses):

    - + - + .on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)));]]>
    • See the section about to learn more about the many ways to create objects in jOOQ.
    • @@ -1788,13 +1765,12 @@ create.select() Surprisingly, SQL does not allow to formally JOIN on well-known foreign key relationship information. Naturally, when you join BOOK to AUTHOR, you will want to do that based on the BOOK.AUTHOR_ID foreign key to AUTHOR.ID primary key relation. Not being able to do this in SQL leads to a lot of repetitive code, re-writing the same JOIN predicate again and again - especially, when your foreign keys contain more than one column. With jOOQ, when you use , you can use foreign key constraint information in JOIN expressions as such:

      - + - + .join(BOOK).onKey();]]>

      In case of ambiguity, you can also supply field references for your foreign keys, or the generated foreign key reference to the onKey() method. @@ -1805,137 +1781,130 @@ JOIN BOOK ON BOOK.AUTHOR_ID = AUTHOR.ID]]> Most often, you will provide jOOQ with JOIN conditions in the JOIN .. ON clause. SQL supports a different means of specifying how two tables are to be joined. This is the JOIN .. USING clause. Instead of a condition, you supply a set of fields whose names are common to both tables to the left and right of a JOIN operation. This can be useful when your database schema has a high degree of relational normalisation. An example:

      - + - + .join(BOOK).using(AUTHOR.AUTHOR_ID);]]>

      In schemas with high degrees of normalisation, you may also choose to use NATURAL JOIN, which takes no JOIN arguments as it joins using all fields that are common to the table expressions to the left and to the right of the JOIN operator. An example:

      - + - + .naturalJoin(BOOK);]]>

      Oracle's partitioned OUTER JOIN

      Oracle SQL ships with a special syntax available for OUTER JOIN clauses. According to the Oracle documentation about partitioned outer joins this can be used to fill gaps for simplified analytical calculations. jOOQ only supports putting the PARTITION BY clause to the right of the OUTER JOIN clause. The following example will create at least one record per AUTHOR and per existing value in BOOK.PUBLISHED_IN, regardless if an AUTHOR has actually published a book in that year.

      - + - + .on(BOOK.AUTHOR_ID.equal(AUTHOR.ID));]]> - +
    The WHERE clause - +

    The WHERE clause can be used for JOIN or filter predicates, in order to restrict the data returned by the supplied to the previously specified and . Here is an example:

    - + - + .and(BOOK.TITLE.equal("1984"));]]>

    The above syntax is convenience provided by jOOQ, allowing you to connect the supplied in the WHERE clause with another condition using an AND operator. You can of course also create a more complex condition and supply that to the WHERE clause directly (observe the different placing of parentheses). The results will be the same:

    - + - + BOOK.TITLE.equal("1984")));]]>

    You will find more information about creating later in the manual.

    -
    +
    The CONNECT BY clause - +

    The Oracle database knows a very succinct syntax for creating hierarchical queries: the CONNECT BY clause, which is fully supported by jOOQ, including all related functions and pseudo-columns. A more or less formal definition of this clause is given here:

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

    An example for an iterative query, iterating through values between 1 and 5 is this:

    - + - + .connectBy(level().lessOrEqual(5));]]>

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

    - + - - +

    The output might then look like this

    -+------------------------------------------------+ ++------------------------------------------------+ |substring | +------------------------------------------------+ |C: | @@ -1945,7 +1914,7 @@ ORDER BY 1]]> |C:/eclipse/eclipse.exe | +------------------------------------------------+ |...21 record(s) truncated... - +

    Some of the supported functions and pseudo-columns are these (available from the ): @@ -1969,38 +1938,36 @@ ORDER BY 1]]> The Oracle database allows for specifying a SIBLINGS keyword in the . Instead of ordering the overall result, this will only order siblings among each other, keeping the hierarchy intact. An example is given here:

    - + - - + -
    +
    The GROUP BY clause - +

    GROUP BY can be used to create unique groups of data, to form aggregations, to remove duplicates and for other reasons. It will transform your previously defined , and return only one record per unique group as specified in this clause. For instance, you can group books by BOOK.AUTHOR_ID:

    - + - + .groupBy(AUTHOR_ID);]]>

    As defined in the SQL standard, when grouping, you may no longer project any columns that are not a formal part of the GROUP BY clause, or . The above example counts all books per author @@ -2011,13 +1978,12 @@ GROUP BY AUTHOR_ID]]> MySQL has a peculiar way of not adhering to this standard behaviour. This is documented in the MySQL manual. In short, with MySQL, you can also project any other field that are not part of the GROUP BY clause. The projected values will just be arbitrary values from within the group. You cannot rely on any ordering. For example:

    - + - + .groupBy(AUTHOR_ID);]]>

    This will return an arbitrary title per author. jOOQ supports this syntax, as jOOQ is not doing any checks internally, about the consistence of tables/fields/functions that you provide it. @@ -2028,68 +1994,64 @@ GROUP BY AUTHOR_ID]]> jOOQ supports empty GROUP BY () clauses as well. This will result in that return only one record.

    - + - + .groupBy();]]>

    ROLLUP(), CUBE() and GROUPING SETS()

    Some databases support the SQL standard grouping functions and some extensions thereof. See the manual's section about for more details.

    -
    +
    The HAVING clause - +

    The HAVING clause is commonly used to further restrict data resulting from a previously issued . An example, selecting only those authors that have written at least two books:

    - + = 2]]> -= 2]]> + .having(count().greaterOrEqual(2));]]>

    According to the SQL standard, you may omit the GROUP BY clause and still issue a HAVING clause. This will implicitly GROUP BY (). jOOQ also supports this syntax. The following example selects one record, only if there are at least 4 books in the books table:

    - + = 4]]> -= 4]]> + .having(count().greaterOrEqual(4));]]> -
    +
    The ORDER BY clause - +

    Databases are allowed to return data in any arbitrary order, unless you explicitly declare that order in the ORDER BY clause. In jOOQ, this is straight-forward:

    - + - + .orderBy(BOOK.AUTHOR_ID.asc(), BOOK.TITLE.desc());]]>

    Any jOOQ can be transformed into an by calling the asc() and desc() methods. @@ -2100,13 +2062,12 @@ ORDER BY AUTHOR_ID ASC, TITLE DESC]]> The SQL standard allows for specifying integer literals (, not !) to reference column indexes from the projection (). This may be useful if you do not want to repeat a lengthy expression, by which you want to order - although most databases also allow for referencing in the ORDER BY clause. An example of this is given here:

    - + - + .orderBy(one().asc(), inline(2).desc());]]>

    Note, how one() is used as a convenience short-cut for inline(1) @@ -2117,87 +2078,84 @@ ORDER BY 1 ASC, 2 DESC]]> A few databases support the SQL standard "null ordering" clause in sort specification lists, to define whether NULL values should come first or last in an ordered result.

    - + - + BOOK.CO_AUTHOR_ID.asc().nullsLast());]]>

    If your database doesn't support this syntax, jOOQ simulates it using a as follows

    - + - + BOOK.CO_AUTHOR_ID.asc().nullsLast());]]>

    Ordering using CASE expressions

    Using in SQL ORDER BY clauses is a common pattern, if you want to introduce some sort indirection / sort mapping into your queries. As with SQL, you can add any type of into your ORDER BY clause. For instance, if you have two favourite books that you always want to appear on top, you could write:

    - + - + .otherwise(2).asc());]]>

    But writing these things can become quite verbose. jOOQ supports a convenient syntax for specifying sort mappings. The same query can be written in jOOQ as such:

    - + .orderBy(BOOK.TITLE.sortAsc("1984", "Animal Farm"));]]>

    More complex sort indirections can be provided using a Map:

    -() {{ put("1984", 1); put("Animal Farm", 13); put("The jOOQ book", 10); - }}));]]> + }}));]]>

    Of course, you can combine this feature with the previously discussed NULLS FIRST / NULLS LAST feature. So, if in fact these two books are the ones you like least, you can put all NULLS FIRST (all the other books):

    - + .orderBy(BOOK.TITLE.sortAsc("1984", "Animal Farm").nullsFirst());]]>

    jOOQ's understanding of SELECT .. ORDER BY

    @@ -2209,23 +2167,23 @@ ORDER BY CASE TITLE

    jOOQ also supports Oracle's SIBLINGS keyword to be used with ORDER BY clauses for

    -
    +
    The LIMIT .. OFFSET clause - +

    While being extremely useful for every application that does paging, or just to limit result sets to reasonable sizes, this clause is not yet part of any SQL standard (up until SQL:2008). Hence, there exist a variety of possible implementations in various SQL dialects, concerning this limit clause. jOOQ chose to implement the LIMIT .. OFFSET clause as understood and supported by MySQL, H2, HSQLDB, Postgres, and SQLite. Here is an example of how to apply limits with jOOQ:

    - +

    This will limit the result to 1 books starting with the 2nd book (starting at offset 0!). limit() is supported in all dialects, offset() in all but Sybase ASE, which has no reasonable means to simulate it. This is how jOOQ simulates the above query in various SQL dialects:

    - 1 AND ROWNUM_98843777 <= 3 -]]> +]]>

    As you can see, jOOQ will take care of the incredibly painful ROW_NUMBER() OVER() (or ROWNUM for Oracle) filtering in subselects for you, you'll just have to write limit(1).offset(2) in any dialect. @@ -2270,39 +2228,37 @@ AND ROWNUM_98843777 <= 3

    As can be seen in the above example, writing correct SQL can be quite tricky, depending on the SQL dialect. For instance, with SQL Server, you cannot have an ORDER BY clause in a subquery, unless you also have a TOP clause. This is illustrated by the fact that jOOQ renders a TOP 100 PERCENT clause for you. The same applies to the fact that ROW_NUMBER() OVER() needs an ORDER BY windowing clause, even if you don't provide one to the jOOQ query. By default, jOOQ adds ordering by the first column of your projection.

    -
    +
    The FOR UPDATE clause - +

    For inter-process synchronisation and other reasons, you may choose to use the SELECT .. FOR UPDATE clause to indicate to the database, that a set of cells or records should be locked by a given transaction for subsequent updates. With jOOQ, this can be achieved as such:

    - + - + .forUpdate();]]>

    The above example will produce a record-lock, locking the whole record for updates. Some databases also support cell-locks using FOR UPDATE OF ..

    - + - + .forUpdate().of(BOOK.TITLE);]]>

    Oracle goes a bit further and also allows to specify the actual locking behaviour. It features these additional clauses, which are all supported by jOOQ: @@ -2316,15 +2272,15 @@ FOR UPDATE OF TITLE]]> With jOOQ, you can use those Oracle extensions as such:

    - +create.select().from(BOOK).where(BOOK.ID.equal(3)).forUpdate().skipLocked();]]>

    FOR UPDATE in CUBRID and SQL Server

    The SQL standard specifies a FOR UPDATE clause to be applicable for cursors. Most databases interpret this as being applicable for all SELECT statements. An exception to this rule are the CUBRID and SQL Server databases, that do not allow for any FOR UPDATE clause in a regular SQL SELECT statement. jOOQ simulates the FOR UPDATE behaviour, by locking record by record with JDBC. JDBC allows for specifying the flags TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE for any statement, and then using ResultSet.updateXXX() methods to produce a cell-lock / row-lock. Here's a simplified example in JDBC:

    - +}]]>

    The main drawback of this approach is the fact that the database has to maintain a scrollable cursor, whose records are locked one by one. This can cause a major risk of deadlocks or race conditions if the JDBC driver can recover from the unsuccessful locking, if two Java threads execute the following statements:

    - +SELECT * FROM author ORDER BY id DESC;]]>

    So use this technique with care, possibly only ever locking single rows! @@ -2361,12 +2317,12 @@ SELECT * FROM author ORDER BY id DESC;]]>

    Note, that jOOQ also supports optimistic locking, if you're doing simple CRUD. This is documented in the section's manual about .

    -
    +
    UNION, INTERSECTION and EXCEPT - +

    SQL allows to perform set operations as understood in standard set theory on result sets. These operations include unions, intersections, subtractions. For two subselects to be combinable by such a set operator, each subselect must return a of the same arity and type.

    @@ -2376,13 +2332,12 @@ SELECT * FROM author ORDER BY id DESC;]]> These operators combine two results into one. While UNION removes all duplicate records resulting from this combination, UNION ALL leaves subselect results as they are. Typically, you should prefer UNION ALL over UNION, if you don't really need to remove duplicates. The following example shows how to use such a UNION operation in jOOQ.

    - + - +create.selectFrom(BOOK).where(BOOK.ID.equal(5)));]]>

    INTERSECT [ ALL ] and EXCEPT [ ALL ]

    @@ -2394,76 +2349,73 @@ create.selectFrom(BOOK).where(BOOK.ID.equal(5)));]]> As previously mentioned in the manual's section about the , jOOQ has slightly changed the semantics of these set operators. While in SQL, a subselect may not contain any or (unless you wrap the subselect into a ), jOOQ allows you to do so. In order to select both the youngest and the oldest author from the database, you can issue the following statement with jOOQ (rendered to the MySQL dialect):

    - + - + .orderBy(AUTHOR.DATE_OF_BIRTH.desc()).limit(1));]]> -
    +
    Oracle-style hints - +

    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 AUTHOR +SELECT /*+ALL_ROWS*/ FIRST_NAME, LAST_NAME + FROM AUTHOR

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

    -create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) +create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .hint("/*+ALL_ROWS*/") - .from(AUTHOR); + .from(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

    -
    +
    The INSERT statement - +

    The INSERT statement is used to insert new records into a database table. Records can either be supplied using a VALUES() constructor, or a SELECT statement. jOOQ supports both types of INSERT statements. An example of an INSERT statement using a VALUES() constructor is given here:

    - + INSERT INTO AUTHOR (ID, FIRST_NAME, LAST_NAME) -VALUES (100, 'Hermann', 'Hesse'); -create.insertInto(AUTHOR, +VALUES (100, 'Hermann', 'Hesse');create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) - .values(100, "Hermann", "Hesse"); + .values(100, "Hermann", "Hesse");

    INSERT multiple rows with the VALUES() constructor

    The SQL standard specifies that multiple rows can be supplied to the VALUES() constructor in an INSERT statement. Here's an example of a multi-record INSERT

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

    jOOQ tries to stay close to actual SQL. In detail, however, Java's expressiveness is limited. That's why the values() clause is repeated for every record in multi-record inserts. @@ -2472,30 +2424,29 @@ VALUES (100, 'Hermann', 'Hesse'), Some RDBMS do not support inserting several records in a single statement. In those cases, jOOQ simulates multi-record INSERTs using the following SQL:

    - + INSERT INTO AUTHOR (ID, FIRST_NAME, LAST_NAME) SELECT 100, 'Hermann', 'Hesse' FROM DUAL UNION ALL -SELECT 101, 'Alfred', 'Döblin' FROM DUAL; -create.insertInto(AUTHOR, +SELECT 101, 'Alfred', 'Döblin' FROM DUAL;create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .values(100, "Hermann", "Hesse") .values(101, "Alfred", "Döblin"); - +

    INSERT using jOOQ's alternative syntax

    MySQL (and some other RDBMS) allow for using a non-SQL-standard, 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(AUTHOR) +create.insertInto(AUTHOR) .set(AUTHOR.ID, 100) .set(AUTHOR.FIRST_NAME, "Hermann") .set(AUTHOR.LAST_NAME, "Hesse") .newRecord() .set(AUTHOR.ID, 101) .set(AUTHOR.FIRST_NAME, "Alfred") - .set(AUTHOR.LAST_NAME, "Döblin"); + .set(AUTHOR.LAST_NAME, "Döblin");

    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. Internally, the two syntaxes are strictly equivalent. @@ -2506,12 +2457,12 @@ SELECT 101, 'Alfred', 'Döblin' FROM DUAL; 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 (i.e. if they support the SQL standard ). Here is an example how to use the ON DUPLICATE KEY UPDATE clause:

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

    The synthetic ON DUPLICATE KEY IGNORE clause

    @@ -2519,18 +2470,18 @@ create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.LAST_NAME) 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 :

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

    Postgres's INSERT .. RETURNING

    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:

    - record = create.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .values("Charlotte", "Roche") @@ -2547,7 +2498,7 @@ create.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .values("Friedrich", "Schiller") // You can request any field. Also trigger-generated values .returning(AUTHOR.ID, AUTHOR.CREATION_DATE) - .fetch();]]> + .fetch();]]>

    Some databases have poor support for returning generated keys after INSERTs. In those cases, jOOQ might need to issue another in order to fetch an @@identity value. Be aware, that this can lead to race-conditions in those databases that cannot properly return generated ID values. For more information, please consider the jOOQ Javadoc for the returning() clause. @@ -2559,53 +2510,49 @@ create.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) In some occasions, you may prefer the INSERT SELECT syntax, for instance, when you copy records from one table to another:

    -create.insertInto(AUTHOR_ARCHIVE) - .select(create.selectFrom(AUTHOR).where(AUTHOR.DECEASED.isTrue())); - -
    +create.insertInto(AUTHOR_ARCHIVE) + .select(create.selectFrom(AUTHOR).where(AUTHOR.DECEASED.isTrue()));
    The UPDATE statement - +

    The UPDATE statement is used to modify one or several pre-existing records in a database table. UPDATE statements are only possible on single tables. Support for multi-table updates will be implemented in the near future. An example update query is given here:

    - + UPDATE AUTHOR SET FIRST_NAME = 'Hermann', LAST_NAME = 'Hesse' - WHERE ID = 3; -create.update(AUTHOR) + WHERE ID = 3;create.update(AUTHOR) .set(AUTHOR.FIRST_NAME, "Hermann") .set(AUTHOR.LAST_NAME, "Hesse") .where(AUTHOR.ID.equal(3)); - + -
    +
    The DELETE statement - +

    The DELETE statement physically removes records from a database table. DELETE statements are only possible on single tables. Support for multi-table deletes will be implemented in the near future. An example delete query is given here:

    - + DELETE AUTHOR - WHERE ID = 100; -create.delete(AUTHOR) + WHERE ID = 100;create.delete(AUTHOR) .where(AUTHOR.ID.equal(100)); - + -
    +
    The 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)

    @@ -2613,15 +2560,14 @@ create.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) 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 {jooq-version}, 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 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(AUTHOR) +WHEN NOT MATCHED THEN INSERT (LAST_NAME) VALUES ('Hitchcock')create.mergeInto(AUTHOR) .using(create().selectOne()) .on(AUTHOR.LAST_NAME.equal("Hitchcock")) .whenMatchedThenUpdate() @@ -2629,39 +2575,38 @@ WHEN NOT MATCHED THEN INSERT (LAST_NAME) VALUES ('Hitchcock') .whenNotMatchedThenInsert(AUTHOR.LAST_NAME) .values("Hitchcock"); - +

    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 AUTHOR (FIRST_NAME, LAST_NAME) KEY (LAST_NAME) -VALUES ('John', 'Hitchcock') -create.mergeInto(AUTHOR, +VALUES ('John', 'Hitchcock')create.mergeInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .key(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

    -
    +
    The TRUNCATE statement - +

    The TRUNCATE statement is the only DDL statement supported by jOOQ so far. It is popular in many databases when you want to bypass constraints for table truncation. Databases may behave differently, when a truncated table is referenced by other tables. For instance, they may fail if records from a truncated table are referenced, even with ON DELETE CASCADE clauses in place. Please, consider your database manual to learn more about its TRUNCATE implementation.

    @@ -2669,44 +2614,42 @@ VALUES ('John', 'Hitchcock') The TRUNCATE syntax is trivial:

    - - TRUNCATE TABLE AUTHOR; - create.truncate(AUTHOR).execute(); - + + TRUNCATE TABLE AUTHOR;create.truncate(AUTHOR).execute(); +

    TRUNCATE is not supported by Ingres and SQLite. jOOQ will execute a DELETE FROM AUTHOR statement instead.

    -
    +
    Table expressions - +

    The following sections explain the various types of table expressions supported by jOOQ

    -
    +
    Generated Tables - +

    Most of the times, when thinking about a you're probably thinking about an actual physical table in your database schema. If you're using jOOQ's , you will have all tables from your database schema available to you as type safe Java objects. You can then use these tables in SQL , or in other , just like any other table expression. An example is given here:

    - + - + .on(AUTHOR.ID.equal(BOOK.AUTHOR_ID));]]>

    The above example shows how AUTHOR and BOOK tables are joined in a . It also shows how you can access physical by dereferencing the relevant Java attributes of their tables. @@ -2714,17 +2657,17 @@ ON (AUTHOR.ID = BOOK.AUTHOR_ID)]]>

    See the manual's section about for more information about what is really generated by the

    -
    +
    Aliased Tables - +

    The strength of jOOQ's becomes more obvious when you perform table aliasing and dereference fields from generated aliased tables. This can best be shown by example:

    - 1920 AND a.first_name = 'Paulo' - ORDER BY b.title]]> - + .orderBy(b.TITLE);]]>

    As you can see in the above example, calling as() on generated tables returns an object of the same type as the table. This means that the resulting object can be used to dereference fields from the aliased table. This is quite powerful in terms of having your Java compiler check the syntax of your SQL statements. If you remove a column from a table, dereferencing that column from that table alias will cause compilation errors. @@ -2755,17 +2697,17 @@ create.select()

    TODO document this

    -
    +
    Joined tables - +

    The that can be used in are the most powerful and best supported means of creating new in SQL. Informally, the following can be said:

    -A(colA1, ..., colAn) "join" B(colB1, ..., colBm) "produces" C(colA1, ..., colAn, colB1, ..., colBm) +A(colA1, ..., colAn) "join" B(colB1, ..., colBm) "produces" C(colA1, ..., colAn, colB1, ..., colBm)

    SQL and relational algebra distinguish between at least the following JOIN types (upper-case: SQL, lower-case: relational algebra): @@ -2783,7 +2725,7 @@ create.select() jOOQ supports all of these JOIN types (except semi-join and anti-join) directly on any :

    - table) // Various overloaded INNER JOINs @@ -2806,41 +2748,40 @@ Table crossJoin(TableLike) // Various overloaded NATURAL JOINs Table naturalJoin(TableLike) Table naturalLeftOuterJoin(TableLike) -Table naturalRightOuterJoin(TableLike)]]> +Table naturalRightOuterJoin(TableLike)]]>

    Note that most of jOOQ's JOIN operations give way to a similar DSL API hierarchy as previously seen in the manual's section about the

    -
    +
    Nested SELECTs - +

    A can appear almost anywhere a can. Such a "nested SELECT" is often called a "derived table". Apart from many convenience methods accepting objects directly, a SELECT statement can always be transformed into a object using the asTable() method.

    Example: Scalar subquery

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

    Example: Derived table

    - + - nested = +]]> nested = create.select(BOOK.AUTHOR_ID, count().as("books")) .from(BOOK) .groupBy(BOOK.AUTHOR_ID).asTable("nested"); @@ -2859,10 +2799,10 @@ ORDER BY nested.books DESC create.select(nested.getFields()) .from(nested) .orderBy(nested.getField("books"));]]> - +

    Example: Correlated subquery

    - + - +]]> Field books = create.selectCount() .from(BOOK) @@ -2882,52 +2821,52 @@ Field books = create.select(AUTHOR.ID, books) .from(AUTHOR) .orderBy(books, AUTHOR.ID));]]> - - + +
    The Oracle 11g PIVOT clause - +

    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 .. +-- SELECT .. FROM table PIVOT (aggregateFunction [, aggregateFunction] FOR column IN (expression [, expression])) --- WHERE .. +-- WHERE ..

    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 slightly different PIVOT clause will be added later. Also, jOOQ may simulate PIVOT for other dialects in the future.

    -
    +
    jOOQ's relational division syntax - +

    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 +Assume the following cross join / cartesian product C = A × B Then it can be said that A = C ÷ B -B = C ÷ A +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) +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" +SELECT DISTINCT C.TEXT FROM C "c1" WHERE NOT EXISTS ( SELECT 1 FROM B WHERE NOT EXISTS ( @@ -2935,7 +2874,7 @@ WHERE NOT EXISTS ( 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. @@ -2949,13 +2888,13 @@ WHERE NOT EXISTS (

  • http://en.wikipedia.org/wiki/Relational_algebra#Division
  • http://www.simple-talk.com/sql/t-sql-programming/divided-we-stand-the-sql-of-relational-division/
  • -
    +
    Array and cursor unnesting - +

    The SQL standard specifies how SQL databases should implement ARRAY and TABLE types, as well as CURSOR types. Put simply, a CURSOR is a pointer to any materialised . Depending on the cursor's features, this table expression can be scrolled through in both directions, records can be locked, updated, removed, inserted, etc. Often, CURSOR types contain s, whereas ARRAY and TABLE types contain simple scalar values, although that is not a requirement

    @@ -2969,21 +2908,20 @@ WHERE NOT EXISTS ( The real power of these types become more obvious when you fetch them from to unnest them as and use them in your . An example is given here, where Oracle's DBMS_XPLAN package is used to fetch a cursor containing data about the most recent execution plan:

    - + - - +

    Note, in order to access the DbmsXplan package, you can use the to generate Oracle's SYS schema.

    -
    +
    The DUAL table - +

    The SQL standard specifies that the is optional in a . However, according to the standard, you may then no longer use some other clauses, such as the . In the real world, there exist three types of databases:

    @@ -2996,7 +2934,7 @@ FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(null, null, 'ALLSTATS'));]]> With jOOQ, you don't have to worry about the above distinction of SQL dialects. jOOQ never requires a FROM clause, but renders the necessary "DUAL" table, if needed. The following program shows how jOOQ renders "DUAL" tables

    - + - - +

    Note, that some databases (H2, MySQL) can normally do without "dual". However, there exist some corner-cases with complex nested SELECT statements, where this will cause syntax errors (or parser bugs). To stay on the safe side, jOOQ will always render "dual" in those dialects.

    -
    +
    Column expressions - +

    Column expressions can be used in various SQL clauses in order to refer to one or several columns. This chapter explains how to form various types of column expressions with jOOQ. A particular type of column expression is given in the section about , where an expression may have a degree of more than one.

    @@ -3046,7 +2983,7 @@ new Factory(SQLDialect.SYBASE ).selectOne().getSQL();]]> jOOQ allows you to freely create arbitrary column expressions using a fluent expression construction API. Many expressions can be formed as functions from , other expressions can be formed based on a pre-existing column expression. For example:

    - field1 = BOOK.TITLE; // A function created from the Factory using "prefix" notation @@ -3058,31 +2995,30 @@ Field field3 = BOOK.TITLE.trim(); // More complex function with advanced DSL syntax Field field4 = listAgg(BOOK.TITLE) .withinGroupOrderBy(BOOK.ID.asc()) - .over().partitionBy(AUTHOR.ID);]]> + .over().partitionBy(AUTHOR.ID);]]>

    In general, it is up to you whether you want to use the "prefix" notation or the "postfix" notation to create new column expressions based on existing ones. The "SQL way" would be to use the "prefix notation", with functions created from the . The "Java way" or "object-oriented way" would be to use the "postfix" notation with functions created from objects. Both ways ultimately create the same query part, though.

    -
    +
    Table columns - +

    Table columns are the most simple implementations of a . They are mainly produced by jOOQ's and can be dereferenced from the generated tables. This manual is full of examples involving table columns. Another example is given in this query:

    - + - - +

    Table columns implement a more specific interface called , which is parameterised with its associated <R extends Record> record type. @@ -3090,45 +3026,43 @@ ORDER BY BOOK.TITLE]]>

    See the manual's section about for more information about what is really generated by the

    -
    +
    Aliased columns - +

    Just like , columns can be renamed using aliases. Here is an example:

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

    Here is how it's done with jOOQ:

    -Record record = create.select( +Record record = create.select( concat(AUTHOR.FIRST_NAME, val(" "), AUTHOR.LAST_NAME).as("author"), count().as("books")) .from(AUTHOR) .join(BOOK).on(AUTHOR.ID.equal(BOOK.AUTHOR_ID)) - .groupBy(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME).fetchAny(); + .groupBy(AUTHOR.FIRST_NAME, 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")); - -
    +System.out.println("Author : " + record.getValue("author")); +System.out.println("Books : " + record.getValue("books"));
    Cast expressions - +

    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.

    @@ -3136,27 +3070,27 @@ System.out.println("Books : " + record.getValue("books")); Sometimes, this automatic mapping might not be what you needed, or jOOQ cannot know the type of a field. In those cases you would write SQL type CASTs like this:

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

    in jOOQ, you can write something like that:

    -create.select(TAuthor.LAST_NAME.cast(PostgresDataType.TEXT)); +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)); +create.select(TAuthor.LAST_NAME.cast(String.class));

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

    - { + { // Cast this field to the type of another field Field cast(Field field); @@ -3176,41 +3110,39 @@ public class Factory { Field castNull(Field field); Field castNull(DataType type); Field castNull(Class type); -}]]> -
    +}]]>
    Arithmetic expressions - +

    Numeric arithmetic expressions

    Your database can do the math for you. 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 +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); +create.select(val(1).add(2).mul(val(5).sub(3)).div(2).mod(10);

    Datetime arithmetic expressions

    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)); - + + 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: @@ -3219,31 +3151,30 @@ public class Factory {

  • INTERVAL YEAR TO MONTH:
  • INTERVAL DAY TO SECOND:
  • -
    +
    String concatenation - +

    The SQL standard defines the concatenation operator to be an infix operator, similar to the ones we've seen in the chapter about . This operator looks like this: ||. Some other dialects do not support this operator, but expect a concat() function, instead. jOOQ renders the right operator / function, depending on your :

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

    There are a variety of general functions supported by jOOQ As discussed in the chapter about functions are mostly simulated in your database, in case they are not natively supported.

    @@ -3260,12 +3191,12 @@ create.select(concat("A", "B", "C"));

    Please refer to the for more details.

    -
    +
    Numeric functions - +

    Math can be done efficiently in the database before returning results to your Java application. In addition to the discussed previously, jOOQ also supports a variety of numeric functions. As discussed in the chapter about numeric functions (as any function type) are mostly simulated in your database, in case they are not natively supported.

    @@ -3307,12 +3238,12 @@ create.select(concat("A", "B", "C"));

    Please refer to the for more details.

    -
    +
    Bitwise functions - +

    Interestingly, bitwise functions and bitwise arithmetic is not very popular among SQL databases. Most databases only support a few bitwise operations, while others ship with the full set of operators. jOOQ's API includes most bitwise operations as listed below. In order to avoid ambiguities with , all bitwise functions are prefixed with "bit"

    @@ -3335,12 +3266,12 @@ create.select(concat("A", "B", "C")); http://blog.jooq.org/2011/10/30/the-comprehensive-sql-bitwise-operations-compatibility-list/

    -
    +
    String functions - +

    String formatting can be done efficiently in the database before returning results to your Java application. As discussed in the chapter about string functions (as any function type) are mostly simulated in your database, in case they are not natively supported.

    @@ -3378,18 +3309,18 @@ create.select(concat("A", "B", "C")); Various databases have some means of searching through columns using regular expressions if the does not provide sufficient pattern matching power. While there are many different functions and operators in the various databases, jOOQ settled for the SQL:2008 standard REGEX_LIKE operator. Being an operator (and not a function), you should use the corresponding method on :

    - +

    Note that the SQL standard specifies that patterns should follow the XQuery standards. In the real world, the POSIX regular expression standard is the most used one, some use Java regular expressions, and only a few ones use Perl regular expressions. jOOQ does not make any assumptions about regular expression syntax. For cross-database compatibility, please read the relevant database manuals carefully, to learn about the appropriate syntax. Please refer to the for more details.

    -
    +
    Date and time functions - +

    This is a list of date and time functions supported by jOOQ's :

    @@ -3408,29 +3339,29 @@ create.select(concat("A", "B", "C"));

    jOOQ fills a gap opened by JDBC, which neglects an important SQL data type as defined by the SQL standards: INTERVAL types. See the manual's section about for more details.

    -
    +
    System functions - +

    This is a list of system functions supported by jOOQ's :

    • CURRENT_USER: Get current user.
    -
    +
    Aggregate functions - +

    Aggregate functions work just like functions, even if they have a slightly different semantics. Here are some example aggregate functions from the :

    - count(); AggregateFunction count(Field field); AggregateFunction max (Field field); @@ -3467,20 +3398,19 @@ AggregateFunction regrR2 (Field y, Field regrSlope (Field y, Field x); AggregateFunction regrSXX (Field y, Field x); AggregateFunction regrSXY (Field y, Field x); -AggregateFunction regrSYY (Field y, Field x);]]> +AggregateFunction regrSYY (Field y, Field x);]]>

    Here's an example, counting the number of books any author has written:

    - + SELECT AUTHOR_ID, COUNT(*) FROM BOOK -GROUP BY AUTHOR_ID -create.select(BOOK.AUTHOR_ID, count()) +GROUP BY AUTHOR_IDcreate.select(BOOK.AUTHOR_ID, count()) .from(BOOK) .groupBy(BOOK.AUTHOR_ID); - +

    Aggregate functions have strong limitations about when they may be used and when not. For instance, you can use aggregate functions in scalar queries. Typically, this means you only select aggregate functions, no or other . Another use case is to use them along with a as seen in the previous example. Note, that jOOQ does not check whether your using of aggregate functions is correct according to the SQL standards, or according to your database's behaviour. @@ -3490,39 +3420,37 @@ GROUP BY AUTHOR_ID

    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 Oracle's LISTAGG() (also known as GROUP_CONCAT in other ). 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, ", ") +GROUP BY AUTHOR_IDcreate.select(listAgg(BOOK.TITLE, ", ") .withinGroupOrderBy(BOOK.TITLE)) .from(BOOK) .groupBy(BOOK.AUTHOR_ID) - +

    The above query might yield:

    -+---------------------+ ++---------------------+ | LISTAGG | +---------------------+ | 1984, Animal Farm | | O Alquimista, Brida | -+---------------------+ ++---------------------+

    FIRST and LAST: Oracle's "ranked" aggregate functions

    Oracle allows for restricting aggregate functions using the KEEP() clause, which is supported by jOOQ. In Oracle, some aggregate functions (MIN, MAX, SUM, AVG, COUNT, VARIANCE, or STDDEV) can be restricted by this clause, hence also allows for specifying it. Here are a couple of examples using this clause:

    - + SUM(BOOK.AMOUNT_SOLD) - KEEP(DENSE_RANK FIRST ORDER BY BOOK.AUTHOR_ID) -sum(BOOK.AMOUNT_SOLD) + KEEP(DENSE_RANK FIRST ORDER BY BOOK.AUTHOR_ID)sum(BOOK.AMOUNT_SOLD) .keepDenseRankFirstOrderBy(BOOK.AUTHOR_ID) - +

    User-defined aggregate functions

    @@ -3533,12 +3461,12 @@ GROUP BY AUTHOR_ID

    In those databases that support , jOOQ's can be transformed into a window function / analytical function by calling over() on it. See the manual's section about for more details.

    -
    +
    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. Note, that H2 and HSQLDB have implemented ROW_NUMBER() functions, without true windowing support.

    @@ -3546,7 +3474,7 @@ GROUP BY AUTHOR_ID As previously discussed, any can be transformed into a window function using the over() method. See the chapter about for details. In addition to those, there are also some more window functions supported by jOOQ, as declared in the :

    - rowNumber(); WindowOverStep rank(); WindowOverStep denseRank(); @@ -3566,7 +3494,7 @@ GROUP BY AUTHOR_ID // Statistical functions WindowOverStep cumeDist(); - WindowOverStep ntile(int number);]]> + WindowOverStep ntile(int number);]]>

    SQL distinguishes between various window function types (e.g. "ranking functions"). Depending on the function, SQL expects mandatory PARTITION BY or ORDER BY clauses within the OVER() clause. jOOQ does not enforce those rules for two reasons: @@ -3583,7 +3511,7 @@ GROUP BY AUTHOR_ID Here are some simple examples of window functions with jOOQ:

    - + -- Sample uses of ROW_NUMBER() ROW_NUMBER() OVER() ROW_NUMBER() OVER(PARTITION BY 1) @@ -3594,8 +3522,7 @@ ROW_NUMBER() OVER(PARTITION BY BOOK.AUTHOR_ID ORDER BY BOOK.ID) FIRST_VALUE(BOOK.ID) OVER() FIRST_VALUE(BOOK.ID IGNORE NULLS) OVER() FIRST_VALUE(BOOK.ID RESPECT NULLS) OVER() - -// Sample uses of rowNumber() +// Sample uses of rowNumber() rowNumber().over() rowNumber().over().partitionByOne() rowNumber().over().partitionBy(BOOK.AUTHOR_ID) @@ -3606,27 +3533,26 @@ firstValue(BOOK.ID).over() firstValue(BOOK.ID).ignoreNulls().over() firstValue(BOOK.ID).respectNulls().over() - +

    An advanced window function example

    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). Window functions are accessible from the previously seen 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, + FROM transactionscreate.select(t.BOOKED_AT, t.AMOUNT, sum(t.AMOUNT).over().partitionByOne() .orderBy(t.BOOKED_AT) .rowsBetweenUnboundedPreceding() .andCurrentRow().as("total") .from(TRANSACTIONS.as("t")); - +

    Window functions created from ordered aggregate functions

    @@ -3634,48 +3560,46 @@ firstValue(BOOK.ID).respectNulls().over() In the previous chapter about , we have seen the concept of "ordered aggregate functions", such as Oracle's LISTAGG(). These functions have a window function / analytical function variant, as well. For example:

    - + SELECT LISTAGG(TITLE, ', ') WITHIN GROUP (ORDER BY TITLE) OVER (PARTITION BY BOOK.AUTHOR_ID) -FROM BOOK -create.select(listAgg(BOOK.TITLE, ", ") +FROM BOOKcreate.select(listAgg(BOOK.TITLE, ", ") .withinGroupOrderBy(BOOK.TITLE) .over().partitionBy(BOOK.AUTHOR_ID)) .from(BOOK) - +

    Window functions created from Oracle's FIRST and LAST aggregate functions

    In the previous chapter about , we have seen the concept of "FIRST and LAST aggregate functions". These functions have a window function / analytical function variant, as well. For example:

    - + SUM(BOOK.AMOUNT_SOLD) KEEP(DENSE_RANK FIRST ORDER BY BOOK.AUTHOR_ID) - OVER(PARTITION BY 1) -sum(BOOK.AMOUNT_SOLD) + OVER(PARTITION BY 1)sum(BOOK.AMOUNT_SOLD) .keepDenseRankFirstOrderBy(BOOK.AUTHOR_ID) .over().partitionByOne() - +

    Window functions created from user-defined aggregate functions

    User-defined aggregate functions also implement , hence they can also be transformed into window functions using over(). This is supported by Oracle in particular. See the manual's section about for more details.

    -
    +
    Grouping functions - +

    ROLLUP() explained in SQL

    The SQL standard defines special functions that can be used in the : the grouping functions. These functions can be used to generate several groupings in a single clause. This can best be explained in SQL. Let's take ROLLUP() for instance:

    - + - - +

    In English, the ROLLUP() grouping function provides N+1 groupings, when N is the number of arguments to the ROLLUP() function. Each grouping has an additional group field from the ROLLUP() argument field list. The results of the second query might look something like this:

    - ++-----------+--------------+----------+]]>

    CUBE() explained in SQL

    CUBE() is different from ROLLUP() in the way that it doesn't just create N+1 groupings, it creates all 2^N possible combinations between all group fields in the CUBE() function argument list. Let's re-consider our second query from before:

    - + - - +

    The results would then hold:

    - ++-----------+--------------+----------+]]>

    GROUPING SETS()

    @@ -3804,7 +3726,7 @@ ORDER BY 1 NULLS FIRST, 2 NULLS FIRST jOOQ fully supports all of these functions, as well as the utility functions GROUPING() and GROUPING_ID(), used for identifying the grouping set ID of a record. The thus includes:

    - rollup(Field... fields); Field cube(Field... fields); Field groupingSets(Field... fields); @@ -3813,66 +3735,64 @@ Field groupingSets(Collection>... fields); // The utility functions generating IDs per GROUPING SET Field grouping(Field); -Field groupingId(Field...);]]> +Field groupingId(Field...);]]>

    MySQL's and CUBRID's WITH ROLLUP syntax

    MySQL and CUBRID don't know any grouping functions, but they support a WITH ROLLUP clause, that is equivalent to simple ROLLUP() grouping functions. jOOQ simulates ROLLUP() in MySQL and CUBRID, by rendering this WITH ROLLUP clause. The following two statements mean the same:

    - + - - -
    + +
    User-defined functions - +

    Some databases support user-defined functions, which can be embedded in any SQL statement, if you're using jOOQ's . Let's say you have the following simple function in Oracle SQL:

    - +]]>

    The above function will be made available from a generated class. You can use it like any other :

    - - - - + + +

    Note that user-defined functions returning or data types can also be used wherever can be used, if they are

    -
    +
    User-defined aggregate functions - +

    Some databases support user-defined aggregate functions, which can then be used along with or as . An example for such a database is Oracle. With Oracle, you can define the following OBJECT type (the example was taken from the Oracle 11g documentation):

    - +END;]]>

    The above OBJECT type is then available to function declarations as such:

    - +PARALLEL_ENABLE AGGREGATE USING U_SECOND_MAX;]]>

    Using the generated aggregate function

    jOOQ's will detect such aggregate functions and generate them differently from regular . They implement the type, as mentioned in the manual's section about . Here's how you can use the SECOND_MAX() aggregate function with jOOQ:

    - + - - -
    + +
    The CASE expression - +

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

    - + - - +

    In jOOQ, both syntaxes are supported (The second one is simulated in Derby, which only knows the first one). 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. @@ -3989,15 +3907,15 @@ create.decode().value(AUTHOR.FIRST_NAME) A CASE expression can be used anywhere where you can place a . For instance, you can SELECT the above expression, if you're selecting from AUTHOR:

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

    The Oracle DECODE() function

    Oracle knows a more succinct, but maybe less readable DECODE() function with a variable number of arguments. This function roughly does the same as the second case expression syntax. jOOQ supports the DECODE() function and simulates it using CASE expressions in all dialects other than Oracle:

    - + - - +

    CASE clauses in an ORDER BY clause

    Sort indirection is often implemented with a CASE clause of a SELECT's ORDER BY clause. See the manual's section about the for more details.

    -
    +
    Sequences and serials - +

    Sequences implement the interface, providing essentially this functionality:

    - currval(); // Get a field for the NEXTVAL sequence property -Field nextval();]]> +Field nextval();]]>

    So if you have a sequence like this in Oracle:

    -CREATE SEQUENCE s_author_id +CREATE SEQUENCE s_author_id

    You can then use your object directly in a SQL statement as such:

    - +]]>
    • For more information about generated sequences, refer to the manual's section about
    • For more information about executing standalone calls to sequences, refer to the manual's section about
    -
    +
    Tuples or row value expressions - +

    According to the SQL standard, row value expressions can have a degree of more than one. This is commonly used in the , where the VALUES row value constructor allows for providing a row value expression as a source for INSERT data. Row value expressions can appear in various other places, though. They are supported by jOOQ as s / rows. jOOQ's allows for the construction of type-safe s up to the degree / arity of 8. Higher-degree s are supported as well, but without any type-safety. types are modelled as follows:

    - Row1 row(T1 t1) { ... } public static Row2 row(T1 t1, T2 t2) { ... } public static Row3 row(T1 t1, T2 t2, T3 t3) { ... } @@ -4082,7 +3999,7 @@ public static Row4 row(T1 t1, T2 t2, T3 t3, T4 // [ ... idem for Row5, Row6, Row7, Row8 ... ] // Degrees of more than 8 are supported without type-safety -public static RowN row(Object... values) { ... }]]> +public static RowN row(Object... values) { ... }]]>

    Using row value expressions in predicates

    @@ -4093,14 +4010,14 @@ public static RowN row(Object... values) { ... }]]>

    The also supports a variant where row value expressions are updated, rather than single columns. See the relevant section for more details

    -
    +
    Conditional expressions - +

    Conditions or conditional expressions are widely used in SQL and in the jOOQ API. They can be used in

    @@ -4137,22 +4054,21 @@ public static RowN row(Object... values) { ... }]]>

    Note that jOOQ does not model these values as actual compatible.

    -
    +
    Condition building - +

    With jOOQ, most are built from , calling various methods on them. For instance, to build a , you can write the following expression:

    - + - - +

    Create conditions from the Factory

    @@ -4168,48 +4084,47 @@ BOOK.TITLE.notEqual("Animal Farm")]]>

    Conditions can also be connected using as will be discussed in a subsequent chapter.

    -
    +
    AND, OR, NOT boolean operators - +

    In SQL, as in most other languages, can be connected using the AND and OR binary operators, as well as the NOT unary operator, to form new conditional expressions. In jOOQ, this is modelled as such:

    - + - - +

    The above example shows that the number of parentheses in Java can quickly explode. Proper indentation may become crucial in making such code readable. In order to understand how jOOQ composes combined conditional expressions, let's assign component expressions first:

    - +Condition combined2 = combined1.andNot(c); // The left-hand side of the AND NOT () operator is already wrapped in parentheses]]>

    The Condition API

    Here are all boolean operators on the interface:

    -) // Combine conditions with OR. Convenience for adding orNot(Condition) // Combine conditions with OR. Convenience for adding an inverted condition to the rhs orNotExists(Select) // Combine conditions with OR. Convenience for adding an inverted exists predicate to the rhs -not() // Invert a condition (synonym for Factory.not(Condition)]]> -
    +not() // Invert a condition (synonym for Factory.not(Condition)]]>
    Comparison predicate - +

    In SQL, comparison predicates are formed using common comparison operators:

    @@ -4248,7 +4162,7 @@ not() // Invert a condition (synonym for Factory.not(Conditi Unfortunately, Java does not support operator overloading, hence these operators are also implemented as methods in jOOQ, like any other SQL syntax elements. The relevant parts of the interface are these:

    -); // = (some column expression) eq or equal(Select); // = (some scalar SELECT statement) ne or notEqual(T); // <> (some bind value) @@ -4265,7 +4179,7 @@ gt or greaterThan(Field); // > (some column expression) gt or greaterThan(Select); // > (some scalar SELECT statement) ge or greaterOrEqual(T); // >= (some bind value) ge or greaterOrEqual(Field); // >= (some column expression) -ge or greaterOrEqual(Select); // >= (some scalar SELECT statement)]]> +ge or greaterOrEqual(Select); // >= (some scalar SELECT statement)]]>

    Note that every operator is represented by two methods. A verbose one (such as equal()) and a two-character one (such as eq()). Both methods are the same. You may choose either one, depending on your taste. The manual will always use the more verbose one. @@ -4281,30 +4195,28 @@ ge or greaterOrEqual(Select); // >= (some scalar SELECT statement)]]> In addition to the above, jOOQ provides a few convenience methods for common operations performed on strings using comparison predicates:

    - + LOWER('animal farm')]]> - LOWER('animal farm')]]> - -
    + +
    Quantified comparison predicate - +

    If the right-hand side of a turns out to be a non-scalar table subquery, you can wrap that subquery in a quantifier, such as ALL, ANY, or SOME. Note that the SQL standard defines ANY and SOME to be equivalent. jOOQ settled for the more intuitive ANY and doesn't support SOME. Here are some examples, supported by jOOQ:

    - + ALL(1920, 1940)]]> - ALL(1920, 1940)]]> - +

    For the example, the right-hand side of the quantified comparison predicates were filled with argument lists. But it is easy to imagine that the source of values results from a . @@ -4315,37 +4227,35 @@ BOOK.PUBLISHED_IN.greaterThanAll(1920, 1940);]]> It is interesting to note that the SQL standard defines the in terms of the ANY-quantified predicate. The following two expressions are equivalent:

    - - - - + + +

    Typically, the is more readable than the quantified comparison predicate.

    -
    +
    NULL predicate - +

    In SQL, you cannot compare NULL with any value using , as the result would yield NULL again, which is neither TRUE nor FALSE (see also the manual's section about ). In order to test a for NULL, use the NULL predicate as such:

    - + - - + -
    +
    DISTINCT predicate - +

    Some databases support the DISTINCT predicate, which serves as a convenient, NULL-safe . With the DISTINCT predicate, the following truth table can be assumed:

    @@ -4359,18 +4269,17 @@ BOOK.TITLE.isNotNull()]]> For instance, you can compare two fields for distinctness, ignoring the fact that any of the two could be NULL, which would lead to funny results. This is supported by jOOQ as such:

    - + - - +

    If your database does not natively support the DISTINCT predicate, jOOQ simulates it with an equivalent , modelling the above truth table:

    - + - - -
    + +
    BETWEEN predicate - +

    The BETWEEN predicate can be seen as syntactic sugar for a pair of . According to the SQL standard, the following two predicates are equivalent:

    - - -= [B] AND [A] <= [C]]]> - + += [B] AND [A] <= [C]]]> +

    Note the inclusiveness of range boundaries in the definition of the BETWEEN predicate. Intuitively, this is supported in jOOQ as such:

    - + - - +

    BETWEEN SYMMETRIC

    The SQL standard defines the SYMMETRIC keyword to be used along with BETWEEN to indicate that you do not care which bound of the range is larger than the other. A database system should simply swap range bounds, in case the first bound is greater than the second one. jOOQ supports this keyword as well, simulating it if necessary.

    - + - - +

    The simulation is done trivially:

    - - - - + + + -
    +
    LIKE predicate - +

    LIKE predicates are popular for simple wildcard-enabled pattern matching. Supported wildcards in all SQL databases are:

    @@ -4452,24 +4356,22 @@ BOOK.PUBLISHED_IN.notBetweenSymmetric(1940).and(1920)]]> With jOOQ, the LIKE predicate can be created from any as such:

    - + - - +

    Escaping operands with the LIKE predicate

    Often, your pattern may contain any of the wildcard characters "_" and "%", in case of which you may want to escape them. jOOQ does not automatically escape patterns in like() and notLike() methods. Instead, you can explicitly define an escape character as such:

    - + - - +

    In the above predicate expressions, the exclamation mark character is passed as the escape character to escape wildcard characters "!_" and "!%", as well as to escape the escape character itself: "!!" @@ -4483,7 +4385,7 @@ BOOK.TITLE.notLike("%The !%-Sign Book%", '!')]]> In addition to the above, jOOQ provides a few convenience methods for common operations performed on strings using the LIKE predicate. Typical operations are "contains predicates", "starts with predicates", "ends with predicates", etc. Here is the full convenience API wrapping LIKE predicates:

    - + - - +

    Note, that jOOQ escapes % and _ characters in value in some of the above predicate implementations. For simplicity, this has been omitted in this manual.

    -
    +
    IN predicate - +

    In SQL, apart from comparing a value against several values, the IN predicate can be used to create semi-joins or anti-joins. jOOQ knows the following methods on the interface, to construct such IN predicates:

    -) // Construct an IN predicate from a collection of bind values +) // Construct an IN predicate from a collection of bind values in(T...) // Construct an IN predicate from bind values in(Field...) // Construct an IN predicate from column expressions in(Select) // Construct an IN predicate from a subselect notIn(Collection) // Construct a NOT IN predicate from a collection of bind values notIn(T...) // Construct a NOT IN predicate from bind values notIn(Field...) // Construct a NOT IN predicate from column expressions -notIn(Select) // Construct a NOT IN predicate from a subselect]]> +notIn(Select) // Construct a NOT IN predicate from a subselect]]>

    A sample IN predicate might look like this:

    - + - - +

    NOT IN and NULL values

    @@ -4541,7 +4441,7 @@ BOOK.TITLE.notIn("Animal Farm", "1984")]]> Beware that you should probably not have any NULL values in the right hand side of a NOT IN predicate, as the whole expression would evaluate to NULL, which is rarely desired. This can be shown informally using the following reasoning:

    --- The following conditional expressions are formally or informally equivalent +-- The following conditional expressions are formally or informally equivalent A NOT IN (B, C) A != ANY(B, C) A != B AND A != C @@ -4550,17 +4450,17 @@ A != B AND A != C A NOT IN (B, NULL) -- Substitute C for NULL A != B AND A != NULL -- From the above rules A != B AND NULL -- [ANY] != NULL yields NULL -NULL -- [ANY] AND NULL yields NULL +NULL -- [ANY] AND NULL yields NULL

    A good way to prevent this from happening is to use the for anti-joins, which is NULL-value insensitive. See the manual's section about to see a boolean truth table.

    -
    +
    EXISTS predicate - +

    Slightly less intuitive, yet more powerful than the previously discussed is the EXISTS predicate, that can be used to form semi-joins or anti-joins. With jOOQ, the EXISTS predicate can be formed in various ways:

    @@ -4574,16 +4474,15 @@ NULL -- [ANY] AND NULL yields NULL An example of an EXISTS predicate can be seen here:

    - + - - +

    Note that in SQL, the projection of a subselect in an EXISTS predicate is irrelevant. To help you write queries like the above, you can use jOOQ's selectZero() or selectOne() methods @@ -4594,60 +4493,59 @@ notExists(create.selectOne().from(BOOK) In theory, the two types of predicates can perform equally well. If your database system ships with a sophisticated cost-based optimiser, it will be able to transform one predicate into the other, if you have all necessary constraints set (e.g. referential constraints, not null constraints). However, in reality, performance between the two might differ substantially. An interesting blog post investigating this topic on the MySQL database can be seen here:
    http://blog.jooq.org/2012/07/27/not-in-vs-not-exists-vs-left-join-is-null-mysql/

    -
    +
    OVERLAPS predicate - +

    When comparing dates, the SQL standard allows for using a special OVERLAPS predicate, which checks whether two date ranges overlap each other. The following can be said:

    - +(DATE '2010-01-02', CAST('+2 00:00:00' AS INTERVAL DAY TO SECOND))]]>

    The OVERLAPS predicate in jOOQ

    jOOQ supports the OVERLAPS predicate on . The following methods are contained in :

    - t1, Field t2); -Condition overlaps(Row2 row);]]> +Condition overlaps(Row2 row);]]>

    This allows for expressing the above predicates as such:

    - +row(Date.valueOf('2010-01-01'), new DayToSecond(2)).overlaps(Date.valueOf('2010-01-02'), new DayToSecond(2))]]>

    jOOQ's extensions to the standard

    Unlike the standard (or any database implementing the standard), jOOQ also supports the OVERLAPS predicate for comparing arbitrary . For instance, (1, 3) OVERLAPS (2, 4) will yield true in jOOQ. This is simulated as such

    - -
    +(C <= B) AND (A <= D)]]>
    Plain SQL - +

    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 a host language (Java in this case), which was not made for exactly the same purposes as its hosted 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 by language constraints of its host language. We have seen many functionalities where the DSL becomes a bit verbose. This can be especially true for:

    @@ -4676,7 +4574,7 @@ row(Date.valueOf('2010-01-01'), new DayToSecond(2)).overlaps(Date.valueOf('2010-

    Plain SQL API methods are usually overloaded in three ways. Let's look at the condition query part constructor:

    - +Condition condition(String sql, QueryPart... parts);]]>

    Please refer to the Javadoc for more details. The following is a more complete listing of plain SQL construction methods from the Factory:

    - resultQuery(String sql, QueryPart... parts); // A query with results. This is the same as resultQuery(...).fetch(); Result fetch(String sql); Result fetch(String sql, Object... bindings); -Result fetch(String sql, QueryPart... parts);]]> +Result fetch(String sql, QueryPart... parts);]]>

    Apart from the general factory methods, plain SQL is also available 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"); @@ -4772,7 +4670,7 @@ create.select(LAST_NAME, COUNT1, COUNT2) // Use plain SQL again as fields in GROUP BY and ORDER BY clauses .groupBy(LAST_NAME) - .orderBy(LAST_NAME);]]> + .orderBy(LAST_NAME);]]>

    Important things to note about plain SQL!

    @@ -4784,12 +4682,12 @@ create.select(LAST_NAME, COUNT1, COUNT2)

  • 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.
  • -
    +
    Bind values and parameters - +

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

    @@ -4808,31 +4706,31 @@ create.select(LAST_NAME, COUNT1, COUNT2)

    The following sections explain how you can introduce bind values in jOOQ, and how you can control the way they are rendered and bound to SQL.

    -
    +
    Indexed parameters - +

    JDBC only knows indexed bind values. A typical example for using bind values with JDBC is this:

    - +stmm.executeQuery();]]>

    With dynamic SQL, keeping track of the number of question marks and their corresponding index may turn out to be hard. jOOQ abstracts this and lets you provide the bind value right where it is needed. A trivial example is this:

    - +create.select().from(BOOK).where(BOOK.ID.equal(val(5))).and(BOOK.TITLE.equal(val("Animal Farm")));]]>

    Note the using of to explicitly create an indexed bind value. You don't have to worry about that index. When the query is , each bind value will render a question mark. When the query , each bind value will generate the appropriate bind value index. @@ -4843,7 +4741,7 @@ create.select().from(BOOK).where(BOOK.ID.equal(val(5))).and(BOOK.TITLE.equal(val Should you decide to run the above query outside of jOOQ, using your own , you can do so as follows:

    - select = create.select().from(BOOK).where(BOOK.ID.equal(5)).and(BOOK.TITLE.equal("Animal Farm")); + select = create.select().from(BOOK).where(BOOK.ID.equal(5)).and(BOOK.TITLE.equal("Animal Farm")); // Render the SQL statement: String sql = select.getSQL(); @@ -4853,34 +4751,34 @@ assertEquals("SELECT * FROM BOOK WHERE ID = ? AND TITLE = ?", sql); List values = select.getBindValues(); assertEquals(2, values.size()); assertEquals(5, values.get(0)); -assertEquals("Animal Farm", values.get(1));]]> +assertEquals("Animal Farm", values.get(1));]]>

    You can also extract specific bind values by index from a query, if you wish to modify their underlying value after creating a query. This can be achieved as such:

    - select = create.select().from(BOOK).where(BOOK.ID.equal(5)).and(BOOK.TITLE.equal("Animal Farm")); + select = create.select().from(BOOK).where(BOOK.ID.equal(5)).and(BOOK.TITLE.equal("Animal Farm")); Param param = select.getParam("2"); // You could now modify the Query's underlying bind value: if ("Animal Farm".equals(param.getValue())) { param.setConverted("1984"); -}]]> +}]]>

    For more details about jOOQ's internals, see the manual's section about .

    - +
    Named parameters - +

    Some SQL access abstractions that are built on top of JDBC, or some that bypass JDBC may support named parameters. jOOQ allows you to give names to your parameters as well, although those names are not rendered to SQL strings by default. Here is an example of how to create named parameters using the type:

    - param1 = query.getParam("lastName"); @@ -4889,41 +4787,40 @@ Param param2 = param("lastName", "Poe"); Query query2 = create.select().from(AUTHOR).where(LAST_NAME.equal(param2)); // You can now change the bind value directly on the Param reference: -param2.setValue("Orwell");]]> +param2.setValue("Orwell");]]>

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

    - +query2.bind("lastName", "Orwell");]]>

    In order to actually render named parameter names in generated SQL, use the method:

    - + - - -
    + +
    Inlined parameters - +

    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:

    @@ -4939,7 +4836,7 @@ WHERE LAST_NAME = :lastName]]> In both cases, your inlined bind values will be properly escaped to avoid SQL syntax errors and SQL injection. Some examples:

    - -
    + .where(LAST_NAME.equal("Poe"));]]>
    SQL injection and plain SQL QueryParts - +

    Special care needs to be taken when using . While jOOQ's API allows you to specify bind values for use with plain SQL, you're not forced to do that. For instance, both of the following queries will lead to the same, valid result:

    - +create.fetch("SELECT * FROM BOOK WHERE ID = 5 AND TITLE = 'Animal Farm'");]]>

    All methods in the jOOQ API that allow for plain (unescaped, untreated) SQL contain a warning message in their relevant Javadoc, to remind you of the risk of SQL injection in what is otherwise a SQL-injection-safe API.

    -
    +
    QueryParts - +

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

    @@ -5001,12 +4897,12 @@ create.fetch("SELECT * FROM BOOK WHERE ID = 5 AND TITLE = 'Animal Farm'");]]> The following sections explain some more details about and , as well as other implementation details about QueryParts in general.

    -
    +
    SQL rendering - +

    Every must implement the method to render its SQL string to a . This RenderContext has two purposes:

    @@ -5018,7 +4914,7 @@ create.fetch("SELECT * FROM BOOK WHERE ID = 5 AND TITLE = 'Animal Farm'");]]> API is given here:

    - +RenderContext castModeSome(SQLDialect... dialects);]]>

    The following additional methods are inherited from a common , which is shared among and :

    - +int peekIndex();]]>

    An example of rendering SQL

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

    --- [...] +-- [...] FROM AUTHOR JOIN BOOK ON AUTHOR.ID = BOOK.AUTHOR_ID --- [...] +-- [...]

    This is how jOOQ renders such a condition:

    - +}]]>

    See the manual's sections about and to learn about how to write your own query parts in order to extend jOOQ.

    -
    +
    Pretty printing SQL - +

    As mentioned in the previous chapter about , there are some elements in the that are used for formatting / pretty-printing rendered SQL. In order to obtain pretty-printed SQL, just use the following :

    - +

    And then, use the above factory to render pretty-printed SQL:

    - + - '1984' group by "TEST"."AUTHOR"."LAST_NAME" having count(*) = 2]]> - +

    The section about shows an example of how such pretty printing can be used to log readable SQL to the stdout.

    -
    +
    Variable binding - +

    Every must implement the method. This BindContext has two purposes:

    @@ -5183,7 +5078,7 @@ having count(*) = 2]]> An overview of the API is given here:

    - type) throws DataAccessException; -BindContext bindValues(Object... values) throws DataAccessException;]]> +BindContext bindValues(Object... values) throws DataAccessException;]]>

    Some additional methods are inherited from a common , which is shared among and . Details are documented in the previous chapter about @@ -5204,43 +5099,43 @@ BindContext bindValues(Object... values) throws DataAccessException;]]> A simple example can be provided by checking out jOOQ's internal representation of a (simplified) . It is used for any comparing two fields as for example the AUTHOR.ID = BOOK.AUTHOR_ID condition here:

    --- [...] +-- [...] WHERE AUTHOR.ID = ? --- [...] +-- [...]

    This is how jOOQ binds values on such a condition:

    - +}]]>

    See the manual's sections about and to learn about how to write your own query parts in order to extend jOOQ.

    -
    +
    Extend jOOQ with custom types - +

    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:

    - extends AbstractField {} + extends AbstractField {} public abstract class CustomCondition extends AbstractCondition {} public abstract class CustomTable> extends TableImpl {} -public abstract class CustomRecord> extends TableRecordImpl {}]]> +public abstract class CustomRecord> extends TableRecordImpl {}]]>

    These classes are declared public and covered by jOOQ's integration tests. When you extend these classes, you will have to provide your own implementations for the and methods, as discussed before:

    - +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. Here's an example showing how to create a field multiplying another field by 2

    - IDx2 = new CustomField(BOOK.ID.getName(), BOOK.ID.getDataType()) { @Override public void toSQL(RenderContext context) { @@ -5290,13 +5185,12 @@ final Field IDx2 = new CustomField(BOOK.ID.getName(), BOOK.ID. }; // Use the above field in a SQL statement: -create.select(IDx2).from(BOOK);]]> -
    +create.select(IDx2).from(BOOK);]]>
    Plain SQL QueryParts - +

    If you don't need the 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. Plain SQL methods in jOOQ's API come in two flavours.

    @@ -5308,29 +5202,29 @@ create.select(IDx2).from(BOOK);]]> The above distinction is best explained using an example:

    - id = val(5); Field title = val("Animal Farm"); -create.selectFrom(BOOK).where("BOOK.ID = {0} AND TITLE = {1}", id, title);]]> +create.selectFrom(BOOK).where("BOOK.ID = {0} AND TITLE = {1}", id, title);]]>

    The above technique allows for creating rather complex SQL clauses that are currently not supported by jOOQ, without extending any of the as indicated in the previous chapter.

    -
    +
    Serializability - +

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

    - select = (Select) in.readObject(); @@ -5339,20 +5233,20 @@ select.execute(); // In order to execute the above select, attach it first Factory create = new Factory(connection, SQLDialect.ORACLE); -create.attach(select);]]> +create.attach(select);]]>

    Automatically attaching QueryParts

    Another way of attaching QueryParts automatically, or rather providing them with a new at will, is to hook into the . More details about this can be found in the manual's chapter about

    -
    +
    SQL building in Scala - +

    jOOQ-Scala is a maven module used for leveraging some advanced Scala features for those users that wish to use jOOQ with Scala.

    @@ -5365,7 +5259,7 @@ create.attach(select);]]> The following depicts a trait which wraps all fields:

    -(value : T) : Condition def <=>(value : Field[T]) : Condition -}]]> +}]]>

    The following depicts a trait which wraps numeric fields:

    ->(value : T) : Field[T] def >>(value : Field[T]) : Field[T] -}]]> +}]]>

    An example query using such overloaded operators would then look like this:

    - 2) or (T_BOOK.TITLE in ("O Alquimista", "Brida")) -fetch]]> +fetch]]>

    Scala 2.10 Macros

    This feature is still being experimented with. With Scala Macros, it might be possible to inline a true SQL dialect into the Scala syntax, backed by the jOOQ API. Stay tuned!

    -
    +
    SQL execution - +

    In a previous section of the manual, we've seen how jOOQ can be used to that can be executed with any API including JDBC or ... jOOQ. This section of the manual deals with various means of actually executing SQL with jOOQ.

    @@ -5512,12 +5406,12 @@ fetch]]>

    The following sections of this manual will show how jOOQ is wrapping JDBC for SQL execution

    -
    +
    Comparison between jOOQ and JDBC - +

    Similarities with JDBC

    Even if there are , there are a lot of similarities between JDBC and jOOQ. Just to name a few: @@ -5539,29 +5433,28 @@ fetch]]>

  • : jOOQ does not formally distinguish between static statements and prepared statements. By default, all statements are prepared statements in jOOQ, internally. Executing a statement as a static statement can be done simply using a
  • : JDBC keeps open resources even if they are already consumed. With JDBC, there is a lot of verbosity around safely closing resources. In jOOQ, resources are closed after consumption, by default. If you want to keep them open after consumption, you have to explicitly say so.
  • -
    +
    Query vs. ResultQuery - +

    Unlike JDBC, jOOQ has a lot of knowledge about a SQL query's structure and internals (see the manual's section about ). Hence, jOOQ distinguishes between these two fundamental types of queries. While every can be executed, only can return results (see the manual's section about to learn more about fetching results). With plain SQL, the distinction can be made clear most easily:

    - resultQuery = create.resultQuery("SELECT * FROM BOOK"); -Result resultQuery.fetch();]]> -
    +Result resultQuery.fetch();]]>
    Fetching - +

    Fetching is something that has been completely neglegted by JDBC and also by various other database abstraction libraries. Fetching is much more than just looping or listing records or mapped objects. There are so many ways you may want to fetch data from a database, it should be considered a first-class feature of any database abstraction API. Just to name a few, here are some of jOOQ's fetching modes:

    @@ -5586,7 +5479,7 @@ Result resultQuery.fetch();]]> These modes of fetching are also documented in subsequent sections of the manual

    - fetch(); // The "standard" fetch when you know your query returns only one record @@ -5613,14 +5506,14 @@ List> fetchMany(); List fetch(RecordMapper mapper); // Execute a ResultQuery with jOOQ, but return a JDBC ResultSet, not a jOOQ object -ResultSet fetchResultSet();]]> +ResultSet fetchResultSet();]]>

    Fetch convenience

    These means of fetching are also available from and APIs

    - List fetch(Field field); List fetch(Field field, Class type); @@ -5654,14 +5547,14 @@ ResultSet fetchResultSet();]]> U fetchOne(int fieldIndex, Converter converter); Object fetchOne(String fieldName); T fetchOne(String fieldName, Class type); - U fetchOne(String fieldName, Converter converter);]]> + U fetchOne(String fieldName, Converter converter);]]>

    Fetch transformations

    These means of fetching are also available from and APIs

    - List fetchInto(Class type); // Transform your records into another table type - Result fetchInto(Table table);]]> + Result fetchInto(Table table);]]>

    Note, that apart from the methods, all fetch() methods will immediately close underlying JDBC result sets.

    -
    +
    Record vs. TableRecord - +

    jOOQ understands that SQL is much more expressive than Java, when it comes to the declarative typing of . As a declarative language, SQL allows for creating ad-hoc row value expressions (records with indexed columns) and records (records with named columns). In Java, this is not possible to the same extent. Yet, still, sometimes you wish to use strongly typed records, when you know that you're selecting only from a single table

    @@ -5707,12 +5600,12 @@ ResultSet fetchResultSet();]]> When fetching data only from a single table, the type is known to jOOQ if you use jOOQ's to generate for your database tables. In order to fetch such strongly typed records, you will have to use the :

    - +System.out.println("Published in: " + book.getPublishedIn());]]>

    When you use the method, jOOQ will return the record type supplied with the argument table. Beware though, that you will no longer be able to use any clause that modifies the type of your . This includes: @@ -5723,17 +5616,17 @@ System.out.println("Published in: " + book.getPublishedIn());]]>

  • -
    +
    Arrays, Maps and Lists - +

    By default, jOOQ returns an object, which is essentially a of . Often, you will find yourself wanting to transform this result object into a type that corresponds more to your specific needs. Or you just want to list all values of one specific column. Here are some examples to illustrate those use cases:

    - titles1 = create.select().from(BOOK).fetch().getValues(BOOK.TITLE); List titles2 = create.select().from(BOOK).fetch(BOOK.TITLE); String[] titles3 = create.select().from(BOOK).fetchArray(BOOK.TITLE); @@ -5753,22 +5646,22 @@ Map map4 = create.selectFrom(BOOK).fetchMap(BOOK.ID, BOOK.T Map> group1 = create.selectFrom(BOOK).fetch().intoGroups(BOOK.AUTHOR_ID); Map> group2 = create.selectFrom(BOOK).fetchGroups(BOOK.AUTHOR_ID); Map> group3 = create.selectFrom(BOOK).fetch().intoGroups(BOOK.AUTHOR_ID, BOOK.TITLE); -Map> group4 = create.selectFrom(BOOK).fetchGroups(BOOK.AUTHOR_ID, BOOK.TITLE);]]> +Map> group4 = create.selectFrom(BOOK).fetchGroups(BOOK.AUTHOR_ID, BOOK.TITLE);]]>

    Note that most of these convenience methods are available both through and , some are even available through as well.

    -
    +
    RecordHandler - +

    In a more functional operating mode, you might want to write callbacks that receive records from your select statement results in order to do some processing. This is a common data access pattern in Spring's JdbcTemplate, and it is also available in jOOQ. With jOOQ, you can implement your own classes and plug them into jOOQ's :

    - { Util.doThingsWithBook(book); }; ); -]]> +]]>

    See also the manual's section about the , which provides similar features

    -
    +
    RecordMapper - +

    In a more functional operating mode, you might want to write callbacks that map records from your select statement results in order to do some processing. This is a common data access pattern in Spring's JdbcTemplate, and it is also available in jOOQ. With jOOQ, you can implement your own classes and plug them into jOOQ's :

    - ids = create.selectFrom(BOOK) .orderBy(BOOK.ID) @@ -5824,17 +5717,17 @@ create.selectFrom(BOOK) create.selectFrom(BOOK) .orderBy(BOOK.ID) .fetch(book -> book.getId()); -]]> +]]>

    See also the manual's section about the , which provides similar features

    -
    +
    POJOs - +

    Fetching data in records is fine as long as your application is not really layered, or as long as you're still writing code in the DAO layer. But if you have a more advanced application architecture, you may not want to allow for jOOQ artefacts to leak into other layers. You may choose to write POJOs (Plain Old Java Objects) as your primary DTOs (Data Transfer Objects), without any dependencies on jOOQ's types, which may even potentially hold a reference to a , and thus a JDBC . Like Hibernate/JPA, jOOQ allows you to operate with POJOs. Unlike Hibernate/JPA, jOOQ does not "attach" those POJOs or create proxies with any magic in them.

    @@ -5847,7 +5740,7 @@ create.selectFrom(BOOK) jOOQ tries to find JPA annotations on your POJO types. If it finds any, they are used as the primary source for mapping meta-information. Only the annotation is used and understood by jOOQ. An example:

    - myBooks = create.select().from(BOOK).fetch().into(MyBook.class); -List myBooks = create.select().from(BOOK).fetchInto(MyBook.class);]]> +List myBooks = create.select().from(BOOK).fetchInto(MyBook.class);]]>

    Just as with any other JPA implementation, you can put the annotation on any class member, including attributes, setters and getters. Please refer to the Javadoc for more details. @@ -5870,7 +5763,7 @@ List myBooks = create.select().from(BOOK).fetchInto(MyBook.class);]]> - myBooks = create.select().from(BOOK).fetch().into(MyBook1.class); -List myBooks = create.select().from(BOOK).fetchInto(MyBook1.class);]]> +List myBooks = create.select().from(BOOK).fetchInto(MyBook1.class);]]>

    Please refer to the Javadoc for more details. @@ -5890,7 +5783,7 @@ List myBooks = create.select().from(BOOK).fetchInto(MyBook1.class);]]>< If jOOQ does not find any default constructor, columns are mapped to the "best-matching" constructor. This allows for using "immutable" POJOs with jOOQ. An example illustrates this:

    - myBooks = create.select(BOOK.ID, BOOK.AUTHOR_ID).from(BOOK).fetch().into(MyBook3.class); List myBooks = create.select(BOOK.ID, BOOK.AUTHOR_ID).from(BOOK).fetchInto(MyBook3.class); -]]> +]]>

    Please refer to the Javadoc for more details. @@ -5934,7 +5827,7 @@ List myBooks = create.select(BOOK.ID, BOOK.AUTHOR_ID).from(BOOK).fetchI jOOQ also allows for fetching data into abstract classes or interfaces, or in other words, "proxyable" types. This means that jOOQ will return a wrapped in a implementing your custom type. An example of this is given here:

    - myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetch().into(MyBook3.class); -List myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchInto(MyBook3.class);]]> +List myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchInto(MyBook3.class);]]>

    Please refer to the Javadoc for more details. @@ -5957,7 +5850,7 @@ List myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchInto( The above examples show how to fetch data into your own custom POJOs / DTOs. When you have modified the data contained in POJOs, you probably want to store those modifications back to the database. An example of this is given here:

    - +create.executeUpdate(book);]]>

    Note: Because of your manual setting of ID = 10, jOOQ's store() method will asume that you want to insert a new record. See the manual's section about for more details on this. @@ -5989,7 +5882,7 @@ create.executeUpdate(book);]]> If you're using jOOQ's , you can configure it to for you. Those DAOs operate on . An example of using such a DAO is given here:

    - +bookDao.delete(book);]]>

    More complex data structures

    jOOQ currently doesn't support more complex data structures, the way Hibernate/JPA attempt to map relational data onto POJOs. While future developments in this direction are not excluded, jOOQ claims that generic mapping strategies lead to an enormous additional complexity that only serves very few use cases. You are likely to find a solution using any of jOOQ's various , with only little boiler-plate code on the client side.

    -
    +
    Lazy fetching - +

    Unlike JDBC's , jOOQ's does not represent an open database cursor with various fetch modes and scroll modes, that needs to be closed after usage. jOOQ's results are simple in-memory Java objects, containing all of the result values. If your result sets are large, or if you have a lot of network latency, you may wish to fetch records one-by-one, or in small chunks. jOOQ supports a type for that purpose. In order to obtain such a reference, use the method. An example is given here:

    - cursor = null; try { @@ -6039,7 +5932,7 @@ finally { if (cursor != null) { cursor.close(); } -}]]> +}]]>

    As a holds an internal reference to an open , it may need to be closed at the end of iteration. If a cursor is completely scrolled through, it will conveniently close the underlying ResultSet. However, you should not rely on that. @@ -6055,16 +5948,16 @@ finally {

  • : You can use your own callbacks to map lazily fetched records.
  • : You can fetch data into your own custom POJO types.
  • -
    +
    Many fetching - +

    Many databases support returning several result sets, or cursors, from single queries. An example for this is Sybase ASE's sp_help command:

    - sp_help 'author' + sp_help 'author' +--------+-----+-----------+-------------+-------------------+ |Name |Owner|Object_type|Object_status|Create_date | @@ -6080,14 +5973,14 @@ finally { |last_name |varchar| 50|NULL| NULL| 0| |date_of_birth|date | 4|NULL| NULL| 1| |year_of_birth|int | 4|NULL| NULL| 1| -+-------------+-------+------+----+-----+-----+]]> ++-------------+-------+------+----+-----+-----+]]>

    The correct (and verbose) way to do this with JDBC is as follows:

    - +statement.close();]]>

    As previously discussed in the chapter about , jOOQ does not rely on an internal state of any JDBC object, which is "externalised" by Javadoc. Instead, it has a straight-forward API allowing you to do the above in a one-liner:

    -> results = create.fetchMany("sp_help 'author'");]]> +> results = create.fetchMany("sp_help 'author'");]]>

    Using generics, the resulting structure is immediately clear.

    -
    +
    Later fetching - +

    Some queries take very long to execute, yet they are not crucial for the continuation of the main program. For instance, you could be generating a complicated report in a Swing application, and while this report is being calculated in your database, you want to display a background progress bar, allowing the user to pursue some other work. This can be achived simply with jOOQ, by creating a , a type that extends . An example is given here:

    - future = create.selectFrom(BOOK).where(... complex predicates ...).fetchLater(); // This example actively waits for the result to be done @@ -6140,27 +6033,25 @@ while (!future.isDone()) { } // The result should be ready, now -Result result = future.get();]]> +Result result = future.get();]]>

    Note, that instead of letting jOOQ spawn a new thread, you can also provide jOOQ with your own :

    - future = create.selectFrom(BOOK).where(... complex predicates ...).fetchLater(service);]]> - -
    +FutureResult future = create.selectFrom(BOOK).where(... complex predicates ...).fetchLater(service);]]>
    ResultSet fetching - +

    When interacting with legacy applications, you may prefer to have jOOQ return a , rather than jOOQ's own types. This can be done simply, in two ways:

    - +rs2.close();]]>

    Transform jOOQ's Result into a JDBC ResultSet

    Instead of operating on a JDBC ResultSet holding an open resource from your database, you can also let jOOQ's wrap itself in a . The advantage of this is that the so-created ResultSet has no open connection to the database. It is a completely in-memory ResultSet:

    - result = create.selectFrom(BOOK).fetch(); -ResultSet rs = result.intoResultSet();]]> +ResultSet rs = result.intoResultSet();]]>

    The inverse: Fetch data from a legacy ResultSet using jOOQ

    The inverse of the above is possible too. Maybe, a legacy part of your application produces JDBC , and you want to turn them into a :

    - result = create.fetch(rs); // As a Cursor -Cursor cursor = create.fetchLazy(rs);]]> - -
    +Cursor cursor = create.fetchLazy(rs);]]>
    Data type conversion - +

    Apart from a few extra features (see the manual's section about and ), jOOQ only supports basic types as supported by the JDBC API. In your application, you may choose to transform these data types into your own ones, without writing too much boiler-plate code. This can be done using jOOQ's types. A converter essentially allows for two-way conversion between two Java data types <T> and <U>. By convention, the <T> type corresponds to the type in your database whereas the >U> type corresponds to your own user type. The Converter API is given here:

    - extends Serializable { + extends Serializable { /** * Convert a database object to a user object @@ -6224,7 +6113,7 @@ Cursor cursor = create.fetchLazy(rs);]]> * The user type */ Class toType(); -}]]> +}]]>

    Such a converter can be used in many parts of the jOOQ API. Some examples have been illustrated in the manual's section about . @@ -6235,7 +6124,7 @@ Cursor cursor = create.fetchLazy(rs);]]> Here is a some more elaborate example involving a Converter for :

    - { @Override @@ -6264,14 +6153,14 @@ public class CalendarConverter implements Converter dates1 = create.selectFrom(BOOK).fetch().getValues(BOOK.PUBLISHING_DATE, new CalendarConverter()); List dates2 = create.selectFrom(BOOK).fetch(BOOK.PUBLISHING_DATE, new CalendarConverter()); -]]> +]]>

    Enum Converters

    jOOQ ships with a built-in default , that you can use to map VARCHAR values to enum literals or NUMBER values to enum ordinals (both modes are supported). Let's say, you want to map a YES / NO / MAYBE column to a custom Enum:

    - +}]]>

    Using Converters in generated source code

    jOOQ also allows for generated source code to reference your own custom converters, in order to permanently replace a <T> type by your own, custom <U> type. See the manual's section about for details.

    -
    +
    Static statements vs. Prepared Statements - +

    With JDBC, you have full control over your SQL statements. You can decide yourself, if you want to execute a static without bind values, or a with (or without) bind values. But you have to decide early, which way to go. And you'll have to prevent SQL injection and syntax errors manually, when inlining your bind variables.

    @@ -6311,7 +6200,7 @@ for (BookRecord book : create.selectFrom(BOOK).fetch()) { With jOOQ, this is easier. As a matter of fact, it is plain simple. With jOOQ, you can just set a flag in your , and all queries produced by that factory will be executed as static statements, with all bind values inlined. An example is given here:

    - + - - +

    Reasons for choosing one or the other

    @@ -6345,12 +6233,12 @@ inlined.select(val(1)).where(val(1).equal(1)).fetch();]]>

    Note that you don't have to inline all your bind values at once. If you know that a bind value is not really a variable and should be inlined explicitly, you can do so by using , as documented in the manual's section about

    -
    +
    Reusing a Query's PreparedStatement - +

    As previously discussed in the chapter about , reusing PreparedStatements is handled a bit differently in jOOQ from how it is handled in JDBC

    @@ -6360,7 +6248,7 @@ inlined.select(val(1)).where(val(1).equal(1)).fetch();]]> With JDBC, you can easily reuse a by not closing it between subsequent executions. An example is given here:

    - +}]]>

    The above technique can be quite useful when you want to reuse expensive database resources. This can be the case when your statement is executed very frequently and your database would take non-negligible time to soft-parse the prepared statement and generate a new statement / cursor resource. @@ -6387,7 +6275,7 @@ finally { This is also modeled in jOOQ. However, the difference to JDBC is that closing a statement is the default action, whereas keeping it open has to be configured explicitly. This is better than JDBC, because the default action should be the one that is used most often. Keeping open statements is rarely done in average applications. Here's an example of how to keep open PreparedStatements with jOOQ:

    - query = create.selectOne().keepStatement(true); // Execute the query twice, against the same underlying PreparedStatement: @@ -6399,17 +6287,17 @@ try { // ... but now, you must not forget to close the query finally { query.close(); -}]]> +}]]>

    The above example shows how a query can be executed twice against the same underlying PreparedStatement. Unlike in other execution scenarios, you must not forget to close this query now

    -
    +
    Using JDBC batch operations - +

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

    @@ -6422,7 +6310,7 @@ finally {

    In code, this looks like the following snippet:

    - +int[] result = stmt.executeBatch();]]>

    This will also be supported by jOOQ

    @@ -6458,7 +6346,7 @@ int[] result = stmt.executeBatch();]]> jOOQ supports executing queries in batch mode as follows:

    - -
    + .execute();]]>
    Sequence execution - +

    Most databases support sequences of some sort, to provide you with unique values to be used for primary keys and other enumerations. If you're using jOOQ's , it will generate a sequence object per sequence for you. There are two ways of using such a sequence object:

    @@ -6490,34 +6377,34 @@ create.batch(create.insertInto(AUTHOR, ID, NAME).values("?", "?")) Instead of actually phrasing a select statement, you can also use the convenience methods:

    - +BigInteger currID = create.currval(S_AUTHOR_ID);]]>

    Inlining sequence references in SQL

    You can inline sequence references in jOOQ SQL statements. The following are examples of how to do that:

    - +]]>

    For more info about inlining sequence references in SQL statements, please refer to the manual's section about .

    -
    +
    Stored procedures and functions - +

    Many RDBMS support the concept of "routines", usually calling them procedures and/or functions. These concepts have been around in programming languages for a while, also outside of databases. Famous languages distinguishing procedures from functions are:

    @@ -6566,14 +6453,14 @@ create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) If you're using jOOQ's , it will generate objects for you. Let's consider the following example:

    - +

    The generated artefacts can then be used as follows:

    - +assertEquals(new BigDecimal("2"), procedure.getId();]]>

    But you can also call the procedure using a generated convenience method in a global Routines class:

    - +assertEquals(new BigDecimal("2"), procedure.getId();]]>

    For more details about for procedures, see the manual's section about . @@ -6605,31 +6492,30 @@ assertEquals(new BigDecimal("2"), procedure.getId();]]> Unlike procedures, functions can be inlined in SQL statements to generate or , if you're using . Assume you have a function like this:

    - +

    The generated artefacts can then be used as follows:

    - + - - +

    For more info about inlining stored function references in SQL statements, please refer to the manual's section about .

    -
    +
    Oracle Packages - +

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

    @@ -6643,17 +6529,17 @@ create.select(authorExists("Paulo")).fetchOne(0, boolean.class);]]>

    For more details about for procedures and packages see the manual's section about .

    -
    +
    Oracle member procedures - +

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

    - MEMBER FUNCTION counBOOKs RETURN NUMBER ) --- The type body is omitted for the example]]> +-- The type body is omitted for the example]]>

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

    - +assertNotNull(author.getLastName());]]>

    For more details about for UDTs see the manual's section about .

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

    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 the ). You can export any Result<Record> into the formats discussed in the subsequent chapters of the manual

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

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

    - + @@ -6725,86 +6609,79 @@ String xml = create.selectFrom(BOOK).fetch().formatXML(); Animal Farm -]]> +]]>

    The same result as an can be obtained using the Result.intoXML() method:

    -// Fetch books and format them as XML -Document xml = create.selectFrom(BOOK).fetch().intoXML(); +// Fetch books and format them as XML +Document xml = create.selectFrom(BOOK).fetch().intoXML();

    See the XSD schema definition here, for a formal definition of the XML export format:
    http://www.jooq.org/xsd/jooq-export-1.6.2.xsd

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

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

    -ID,AUTHOR_ID,TITLE +ID,AUTHOR_ID,TITLE 1,1,1984 -2,1,Animal Farm +2,1,Animal Farm

    In addition to the standard behaviour, you can also specify a separator character, as well as a special string to represent NULL values (which cannot be represented in standard CSV):

    -// Use ";" as the separator character +// Use ";" as the separator character String csv = create.selectFrom(BOOK).fetch().formatCSV(';'); // Specify "{null}" as a representation for NULL values -String csv = create.selectFrom(BOOK).fetch().formatCSV(';', "{null}"); - -
    +String csv = create.selectFrom(BOOK).fetch().formatCSV(';', "{null}");
    Exporting JSON - - -// Fetch books and format them as JSON -String json = create.selectFrom(BOOK).fetch().formatJSON(); + // Fetch books and format them as JSON +String json = create.selectFrom(BOOK).fetch().formatJSON();

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

    -{"fields":[{"name":"field-1","type":"type-1"}, +{"fields":[{"name":"field-1","type":"type-1"}, {"name":"field-2","type":"type-2"}, ..., {"name":"field-n","type":"type-n"}], "records":[[value-1-1,value-1-2,...,value-1-n], - [value-2-1,value-2-2,...,value-2-n]]} + [value-2-1,value-2-2,...,value-2-n]]}

    Note: This format has changed in jOOQ 2.6.0

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

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

    - + ID @@ -6824,76 +6701,72 @@ String html = create.selectFrom(BOOK).fetch().formatHTML(); Animal Farm -]]> - -
    +]]>
    Exporting Text - - -// Fetch books and format them as text -String text = create.selectFrom(BOOK).fetch().format(); + // Fetch books and format them as text +String text = create.selectFrom(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| -+---+---------+-----------+ ++---+---------+-----------+

    A simple text representation can also be obtained by calling toString() on a Result object. See also the manual's section about

    -
    +
    Importing data - +

    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 the formats described in the subsequent sections of this manual.

    -
    +
    Importing CSV - +

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

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

    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, dialect); +Factory create = new Factory(connection, dialect); // Load data into the AUTHOR table from an input stream // holding the CSV data. create.loadInto(AUTHOR) .loadCSV(inputstream) .fields(ID, AUTHOR_ID, TITLE) - .execute(); + .execute();

    Here are various other examples:

    -// Ignore the AUTHOR_ID column from the CSV file when inserting +// Ignore the AUTHOR_ID column from the CSV file when inserting create.loadInto(AUTHOR) .loadCSV(inputstream) .fields(ID, null, TITLE) @@ -6934,13 +6807,13 @@ create.loadInto(AUTHOR) .loadCSV(inputstream) .fields(ID, null, TITLE) - .execute(); + .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(); + loader = /* .. */ .execute(); // The number of processed rows int processed = loader.processed(); @@ -6963,23 +6836,21 @@ int rowIndex = error.rowIndex(); String[] row = error.row(); // The query that caused the error -Query query = error.query();]]> - -
    +Query query = error.query();]]>
    Importing XML - +

    This is not yet supported

    -
    +
    CRUD with UpdatableRecords - +

    Your database application probably consists of 50% - 80% CRUD, whereas only the remaining 20% - 50% of querying is actual querying. Most often, you will operate on records of tables without using any advanced relational concepts. This is called CRUD for

    @@ -6998,13 +6869,13 @@ Query query = error.query();]]> In normalised databases, every table has a primary key by which a tuple/record within that table can be uniquely identified. In simple cases, this is a (possibly auto-generated) number called ID. But in many cases, primary keys include several non-numeric columns. An important feature of such keys is the fact that in most databases, they are enforced using an index that allows for very fast random access to the table. A typical way to access / modify / delete a book is this:

    - +DELETE FROM BOOK WHERE ID = 5;]]>

    Normalised databases assume that a primary key is unique "forever", i.e. that a key, once inserted into a table, will never be changed or re-inserted after deletion. In order to use jOOQ's operations correctly, you should design your database accordingly. @@ -7022,24 +6893,24 @@ DELETE FROM BOOK WHERE ID = 5;]]>

    For simplicity, the term "primary key" will be used in the sense of such a "main unique key" in this manual.

    -
    +
    Simple CRUD - +

    If you're using jOOQ's , it will generate implementations for every table that has a primary key. When such a record form the database, these records are "attached" to the that created them. This means that they hold an internal reference to the same database connection that was used to fetch them. This connection is used internally by any of the following methods of the UpdatableRecord:

    - +int delete() throws DataAccessException;]]>

    See the manual's section about for some more insight on "attached" objects. @@ -7050,7 +6921,7 @@ int delete() throws DataAccessException;]]> Storing a record will perform an or an . In general, new records are always inserted, whereas records loaded from the database are always updated. This is best visualised in code:

    - +book2.store();]]>

    Some remarks about storing: @@ -7086,11 +6957,11 @@ book2.store();]]> Deleting a record will remove it from the database. Here's how you delete records:

    - +book.delete();]]>

    Refreshing

    @@ -7100,53 +6971,52 @@ book.delete();]]> In order to perform a refresh, use the following Java code:

    - +book.refresh();]]>

    CRUD and SELECT statements

    CRUD operations can be combined with regular querying, if you select records from single database tables, as explained in the manual's section about . For this, you will need to use the selectFrom() method from the :

    - -
    +}]]>
    IDENTITY values - +

    Many databases support the concept of IDENTITY values, or key values. This is reflected by JDBC's method. jOOQ abstracts using this method as many databases and JDBC drivers behave differently with respect to generated keys. Let's assume the following SQL Server BOOK table:

    - +)]]>

    If you're using jOOQ's , the above table will generate a with an IDENTITY column. This information is used by jOOQ internally, to update IDs after calling :

    - +System.out.println(book.getId());]]>

    Database compatibility

    @@ -7155,8 +7025,8 @@ System.out.println(book.getId());]]>

    These SQL dialects implement the standard very neatly.

    - +

    H2, MySQL, Postgres, SQL Server, Sybase ASE, Sybase SQL Anywhere @@ -7164,7 +7034,7 @@ id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1)]]>

    These SQL dialects implement identites, but the DDL syntax doesn’t follow the standard

    - +id INTEGER NOT NULL IDENTITY]]>

    Oracle @@ -7188,7 +7058,7 @@ id INTEGER NOT NULL IDENTITY]]>

    Oracle does not know any identity columns at all. Instead, you will have to use a trigger and update the ID column yourself, using a custom sequence. Something along these lines:

    - +END my_trigger;]]>

    Note, that this approach can be employed in most databases supporting sequences and triggers! It is a lot more flexible than standard identities

    -
    +
    Non-updatable records - +

    Tables without UNIQUE keys are considered non-updatable by jOOQ, as jOOQ has no way of uniquely identifying such a record within the database. If you're using jOOQ's , such tables will generate classes, instead of classes. When you fetch from such a table, the returned records will not allow for calling any of the methods.

    @@ -7273,12 +7141,12 @@ List books = coAuthor.fetchBookListByCoAuthorId();]]>

    Note, that some databases use internal rowid or object-id values to identify such records. jOOQ does not support these vendor-specific record meta-data.

    -
    +
    Optimistic locking - +

    jOOQ allows you to perform operations using optimistic locking. You can immediately take advantage of this feature by activating the relevant . Without any further knowledge of the underlying data semantics, this will have the following impact on store() and delete() methods:

    @@ -7293,7 +7161,7 @@ List books = coAuthor.fetchBookListByCoAuthorId();]]> The above changes to jOOQ's behaviour are transparent to the API, the only thing you need to do for it to be activated is to set the Settings flag. Here is an example illustrating optimistic locking:

    - +book2.store();]]>

    Optimised optimistic locking using TIMESTAMP fields

    If you're using jOOQ's , you can take indicate TIMESTAMP or UPDATE COUNTER fields for every generated table in the . Let's say we have this table:

    - +)]]>

    The MODIFIED column will contain a timestamp indicating the last modification timestamp for any book in the BOOK table. If you're using jOOQ and it's , jOOQ will then generate this TIMESTAMP value for you, automatically. However, instead of running an additional statement prior to an UPDATE or DELETE statement, jOOQ adds a WHERE-clause to the UPDATE or DELETE statement, checking for TIMESTAMP's integrity. This can be best illustrated with an example:

    - +book2.store();]]>

    As before, without the added TIMESTAMP column, optimistic locking is transparent to the API. @@ -7356,17 +7224,17 @@ book2.store();]]>

    Note, for explicit pessimistic locking, please consider the manual's section about the . For more details about how to configure TIMESTAMP or VERSION fields, consider the manual's section about .

    -
    +
    Batch execution - +

    When inserting, updating, deleting a lot of records, you may wish to profit from JDBC batch operations, which can be performed by jOOQ. These are available through jOOQ's as shown in the following example:

    - books = create.fetch(BOOK); // Modify the above books, and add some new ones: @@ -7374,24 +7242,24 @@ modify(books); addMore(books); // Batch-update and/or insert all of the above books -create.batchStore(books);]]> +create.batchStore(books);]]>

    Internally, jOOQ will render all the required SQL statements and execute them as a regular .

    -
    +
    DAOs - +

    If you're using jOOQ's , you can configure it to generate and DAOs for you. jOOQ then generates one DAO per , i.e. per table with a single-column primary key. Generated DAOs implement a common jOOQ type called . This type contains the following methods:

    - corresponds to the DAO's related table + corresponds to the DAO's related table //

    corresponds to the DAO's related generated POJO type // corresponds to the DAO's related table's primary key type. // Note that multi-column primary keys are not yet supported by DAOs @@ -7427,13 +7295,13 @@ public interface DAO, P, T> { // These methods provide DAO meta-information Table getTable(); Class

    getType(); -}]]> +}]]>

    Besides these base methods, generated DAO classes implement various useful fetch methods. An incomplete example is given here, for the BOOK table:

    - { // Columns with primary / unique keys produce fetchOne() methods @@ -7442,12 +7310,12 @@ public class BookDao extends DAOImpl { // Other columns produce fetch() methods, returning several records public List fetchByAuthorId(Integer... values) { ... } public List fetchByTitle(String... values) { ... } -}]]> +}]]>

    Note that you can further subtype those pre-generated DAO classes, to add more useful DAO methods to them. Using such a DAO is simple:

    - - -
    +bookDao.delete(book);]]>
    Exception handling - +

    Checked vs. unchecked exceptions

    This is an eternal and religious debate. Pros and cons have been discussed time and again, and it still is a matter of taste, today. In this case, jOOQ clearly takes a side. jOOQ's exception strategy is simple: @@ -7502,12 +7368,12 @@ bookDao.delete(book);]]>

    The following section about documents means of overriding jOOQ's exception handling, if you wish to deal separately with some types of constraint violations, or if you raise business errors from your database, etc.

    -
    +
    ExecuteListeners - +

    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, triggers, etc. Advanced ExecuteListeners can also provide custom implementations of Connection, PreparedStatement and ResultSet to jOOQ in apropriate methods.

    @@ -7518,7 +7384,7 @@ bookDao.delete(book);]]> Here is a sample implementation of an ExecuteListener, that is simply counting the number of queries per type that are being executed using jOOQ:

    - +}]]>

    Now, configure jOOQ's runtime to load your listener

    - + 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 - 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 +15:16:52,983 INFO - OTHER : 30 executions

    Please read the for more details @@ -7581,7 +7447,7 @@ for (ExecuteType type : ExecuteType.values()) { The following depicts an example of a custom ExecuteListener, which pretty-prints all queries being executed by jOOQ to stdout:

    - +}]]>

    See also the manual's sections about and the for more sample implementations of actual ExecuteListeners.

    -
    +
    Logging - +

    jOOQ logs all SQL queries and fetched result sets to its internal DEBUG logger, which is implemented as an . By default, execute logging is activated in the . In order to see any DEBUG log output, put either log4j or slf4j on jOOQ's classpath along with their respective configuration. A sample log4j configuration can be seen here:

    - + @@ -7643,20 +7509,20 @@ public class PrettyPrinter extends DefaultExecuteListener { -]]> +]]>

    With the above configuration, let's fetch some data with jOOQ

    - +

    The above query may result in the following log output:

    - with bind values : select "BOOK"."ID", "BOOK"."TITLE" from "BOOK" order by "BOOK"."ID" asc, limit 2 offset 1 Query executed : Total: 1.439ms Fetched result : +----+------------+ @@ -7666,7 +7532,7 @@ Fetched result : +----+------------+ : | 3|O Alquimista| : +----+------------+ Finishing : Total: 4.814ms, +3.375ms -]]> +]]>

    Essentially, jOOQ will log @@ -7682,12 +7548,12 @@ Finishing : Total: 4.814ms, +3.375ms

    If you wish to use your own logger (e.g. avoiding printing out sensitive data), you can deactivate jOOQ's logger using and implement your own .

    -
    +
    Performance considerations - +

    Many users may have switched from higher-level abstractions such as Hibernate to jOOQ, because of Hibernate's hard-to-manage performance, when it comes to large database schemas and complex second-level caching strategies. jOOQ is not a lightweight database abstraction framework, and it comes with its own overhead. Please be sure to consider the following points:

    @@ -7702,14 +7568,14 @@ Finishing : Total: 4.814ms, +3.375ms

    Don't be put off by the above paragraphs. You should optimise wisely, i.e. only in places where you really need very high throughput to your database. jOOQ's overhead compared to plain JDBC is typically less than 1ms per query.

    -
    +
    Code generation - +

    While optional, source code generation is one of jOOQ's main assets if you wish to increase developer productivity. jOOQ's code generator takes your database schema and reverse-engineers it into a set of Java classes modelling , , , , , , user-defined types and many more.

    @@ -7723,12 +7589,12 @@ Finishing : Total: 4.814ms, +3.375ms

    The following chapters will show how to configure the code generator and how to generate various artefacts.

    -
    +
    Configuration and setup of the generator - +

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

    @@ -7755,7 +7621,7 @@ Finishing : Total: 4.814ms, +3.375ms You need to tell jOOQ some things about your database connection. Here's an example of how to do it for an Oracle database

    - + @@ -7830,7 +7696,7 @@ Finishing : Total: 4.814ms, +3.375ms [/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 for a formal specification at:
    @@ -7842,7 +7708,7 @@ Finishing : Total: 4.814ms, +3.375ms Code generation works by calling this class with the above property file as argument.

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

    Be sure that these elements are located on the classpath: @@ -7905,7 +7771,7 @@ Finishing : Total: 4.814ms, +3.375ms 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:

    - + @@ -7928,26 +7794,26 @@ Finishing : Total: 4.814ms, +3.375ms generatordatabaseinputschema="test" generatortargetpackage="org.jooq.test.generatedclasses" generatortargetdirectory="${basedir}/src"/> -]]> +]]>

    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 @@ -7999,7 +7865,7 @@ Finishing : Total: 4.814ms, +3.375ms -]]> +]]>

    See the full example of a pom.xml including the jOOQ-codegen artefact here:
    @@ -8012,7 +7878,7 @@ Finishing : Total: 4.814ms, +3.375ms 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 +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 @@ -8022,17 +7888,17 @@ Finishing : Total: 4.814ms, +3.375ms

    Be sure, both jooq-{jooq-version}.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.

    -
    +
    Advanced generator configuration - +

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

    - + @@ -8044,13 +7910,13 @@ Finishing : Total: 4.814ms, +3.375ms org.jooq.util.DefaultGeneratorStrategy -]]> +]]>

    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:

    - +}]]>

    jooq-meta configuration

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

    - + ... -]]> +]]>

    Check out the some of the manual's "advanced" sections to find out more about the advanced configuration parameters. @@ -8229,7 +8095,7 @@ public class AsInDatabaseStrategy extends DefaultGeneratorStrategy { Also, you can add some optional advanced configuration parameters for the generator:

    - + false -]]> -
    +]]>
    Generated global artefacts - +

    For increased convenience at the use-site, jOOQ generates "global" artefacts at the code generation root location, referencing tables, routines, sequences, etc. In detail, these global artefacts include the following:

    @@ -8312,7 +8177,7 @@ public class AsInDatabaseStrategy extends DefaultGeneratorStrategy { When referencing global artefacts from your client application, you would typically static import them as such:

    - -
    + .values(com.example.generated.Sequences.MY_SEQUENCE.nextval(), com.example.generated.Routines.myFunction())]]>
    Generated tables - +

    Every table in your database will generate a implementation that looks like this:

    - { + { // The singleton instance public static final Book BOOK = new Book(); @@ -8351,7 +8215,7 @@ create.insertInto(com.example.generated.Tables.MY_TABLE) } // [...] -}]]> +}]]>

    Flags influencing generated tables

    @@ -8371,17 +8235,17 @@ create.insertInto(com.example.generated.Tables.MY_TABLE)

    Table generation cannot be deactivated

    -
    +
    Generated records - +

    Every table in your database will generate a implementation that looks like this:

    - @@ -8422,7 +8286,7 @@ implements IBook { } // [...] -}]]> +}]]>

    Flags influencing generated records

    @@ -8442,17 +8306,17 @@ implements IBook {

    Record generation can be deactivated using the records flag

    -
    +
    Generated POJOs - +

    Every table in your database will generate a POJO implementation that looks like this:

    - +}]]>

    Flags influencing generated POJOs

    @@ -8505,24 +8369,24 @@ public class Book implements java.io.Serializable

    POJO generation can be activated using the pojos flag

    -
    +
    Generated Interfaces - +

    Every table in your database will generate an interface that looks like this:

    - +}]]>

    Flags influencing generated interfaces

    @@ -8537,18 +8401,18 @@ public class Book implements java.io.Serializable

    POJO generation can be activated using the interfaces flag

    -
    +
    Generated DAOs - +

    Generated DAOs

    Every table in your database will generate a implementation that looks like this:

    - { + { // Generated constructors public BookDao() { @@ -8573,43 +8437,43 @@ public class Book implements java.io.Serializable } // [...] -}]]> +}]]>

    Flags controlling DAO generation

    DAO generation can be activated using the daos flag

    -
    +
    Generated sequences - +

    Every sequence in your database will generate a implementation that looks like this:

    - S_AUTHOR_ID = new SequenceImpl("S_AUTHOR_ID", TEST, SQLDataType.INTEGER); -}]]> +}]]>

    Flags controlling sequence generation

    Sequence generation cannot be deactivated

    -
    +
    Generated procedures - +

    Every procedure or function (routine) in your database will generate a implementation that looks like this:

    - { + { // All IN, IN OUT, OUT parameters and function return values generate a static member public static final Parameter AUTHOR_NAME = createParameter("AUTHOR_NAME", SQLDataType.VARCHAR); @@ -8634,7 +8498,7 @@ public class Book implements java.io.Serializable } // [...] -}]]> +}]]>

    Package and member procedures or functions

    @@ -8645,17 +8509,17 @@ public class Book implements java.io.Serializable

    Routine generation cannot be deactivated

    -
    +
    Generated UDTs - +

    Every UDT in your database will generate a implementation that looks like this:

    - { + { // The singleton UDT instance public static final UAddressType U_ADDRESS_TYPE = new UAddressType(); @@ -8669,13 +8533,13 @@ public class Book implements java.io.Serializable createField("COUNTRY", SQLDataType.VARCHAR, U_ADDRESS_TYPE); // [...] -}]]> +}]]>

    Besides the implementation, a implementation is also generated

    - { + { // Every attribute generates a getter and a setter @@ -8687,18 +8551,18 @@ public class Book implements java.io.Serializable public String getCountry() {...} // [...] -}]]> +}]]>

    Flags controlling UDT generation

    UDT generation cannot be deactivated

    -
    +
    Master data and enumeration tables - +

    NOTE: This feature is deprecated in jOOQ 2.5.0 and will be removed as of jOOQ 3.0

    @@ -8711,7 +8575,7 @@ public class Book implements java.io.Serializable As previously discussed, you can configure master data tables as follows:

    - + @@ -8727,13 +8591,13 @@ public class Book implements java.io.Serializable [ ... ... ] - ]]> + ]]>

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

    - { + { /** * English @@ -8761,7 +8625,7 @@ public class Book implements java.io.Serializable 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. @@ -8781,39 +8645,39 @@ public class Book implements java.io.Serializable 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 BookRecord directly:

    - { + { // [...] public Language getLanguageId() { // [...] public void setLanguageId(Language 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 - +

    When using a custom type in jOOQ, you need to let jOOQ know about its associated . Ad-hoc usages of such converters has been discussed in the chapter about . 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_

    - + @@ -8836,41 +8700,39 @@ public class Book implements java.io.Serializable .*\.DATE_OF_.* -]]> +]]>

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

    - { + { // [...] public final TableField DATE_OF_BIRTH = // [...] // [...] -}]]> +}]]>

    This means that the bound type 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(AUTHOR) .where(AUTHOR.DATE_OF_BIRTH.greaterThan(new GregorianCalendar(1980, 0, 1))) - .fetch(AUTHOR.DATE_OF_BIRTH);]]> - -
    + .fetch(AUTHOR.DATE_OF_BIRTH);]]>
    Mapping generated schemata and tables - +

    We've seen previously in the chapter about , that schemata and tables can be mapped at runtime to other names. But 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 @@ -8878,25 +8740,23 @@ create.selectFrom(AUTHOR) PROD -]]> - -
    +]]>
    Tools - +

    These chapters hold some information about tools to be used with jOOQ

    -
    +
    jOOQ Console - +

    The 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:

    @@ -8936,26 +8796,26 @@ create.selectFrom(AUTHOR) Both modes will require that you set the in the Factory's settings. When using XML settings:

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

    Or when using programmatic settings:

    - +Factory factory = new Factory(connection, dialect, 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: @@ -9016,36 +8876,36 @@ catch (Exception ignore) {} 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 +// Create a new RemoteDebuggerServer in your application that listens to // incoming connections on a given port -SERVER = new RemoteDebuggerServer(DEBUGGER_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] +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.

    -
    +
    Reference - +

    These chapters hold some general jOOQ reference information

    -
    +
    Supported RDBMS - +

    A list of supported databases

    Every RDMBS out there has its own little specialties. jOOQ considers those specialties as much as possible, while trying to standardise the behaviour in jOOQ. In order to increase the quality of jOOQ, some 70 unit tests are run for syntax and variable binding verification, as well as some 180 integration tests with an overall of around 1200 queries for any of these databases: @@ -9104,12 +8964,12 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);

    This section will soon contain a feature matrix, documenting what feature is available for which database.

    -
    +
    Data types - +

    There is always a small mismatch between SQL data types and Java data types. This is for two reasons:

    @@ -9120,21 +8980,21 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);

    This chapter should document the most important notes about SQL, JDBC and jOOQ data types.

    -
    +
    BLOBs and CLOBs - +

    jOOQ currently doesn't explicitly support JDBC BLOB and CLOB data types. If you use any of these data types in your database, jOOQ will map them to byte[] and String instead. In simple cases (small data), this simplification is sufficient. In more sophisticated cases, you may have to bypass jOOQ, in order to deal with these data types and their respective resources. True support for LOBs is on the roadmap, though.

    -
    +
    Unsigned integer types - +

    Some databases explicitly support unsigned integer data types. In most normal JDBC-based applications, they would just be mapped to their signed counterparts letting bit-wise shifting and tweaking to the user. jOOQ ships with a set of unsigned implementations modelling the following types:

    @@ -9153,12 +9013,12 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);
  • UInteger wraps
  • ULong wraps
  • -
    +
    INTERVAL data types - +

    jOOQ fills a gap opened by JDBC, which neglects an important SQL data type as defined by the SQL standards: INTERVAL types. SQL knows two different types of intervals:

    @@ -9183,51 +9043,51 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);
  • INTERVAL * or / NUMERIC => INTERVAL
  • NUMERIC * INTERVAL => INTERVAL
  • -
    +
    XML data types - +

    XML data types are currently not supported

    -
    +
    Geospacial data types - +

    Geospacial data types

    Geospacial data types are currently not supported

    -
    +
    CURSOR data types - +

    Some databases support cursors returned from stored procedures. They are mapped to the following jOOQ data type:

    -> cursor;]]> +> cursor;]]>

    In fact, such a cursor will be fetched immediately by jOOQ and wrapped in an object.

    -
    +
    ARRAY and TABLE data types - +

    The SQL standard specifies ARRAY data types, that can be mapped to Java arrays as such:

    - intArray;]]> + intArray;]]>

    The above array type is supported by these SQL dialects: @@ -9242,23 +9102,23 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);

    Oracle has strongly-typed arrays and table types (as opposed to the previously seen anonymously typed arrays). These arrays are wrapped by types.

    -
    +
    jOOQ's BNF pseudo-notation - +

    This chapter will soon contain an overview over jOOQ's API using a pseudo BNF notation.

    -
    +
    Credits - +

    jOOQ lives in a very challenging ecosystem. The Java to SQL interface is still one of the most important system interfaces. Yet there are still a lot of open questions, best practices and no "true" standard has been established. This situation gave way to a lot of tools, APIs, utilities which essentially tackle the same problem domain as jOOQ. jOOQ has gotten great inspiration from pre-existing tools and this section should give them some credit. Here is a list of inspirational tools in alphabetical order:

    @@ -9271,7 +9131,7 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);
  • QueryDSL: A "LINQ-port" to Java. It has a similar fluent API, a similar code-generation facility, yet quite a different purpose. While jOOQ is all about SQL, QueryDSL (like LINQ) is mostly about querying.
  • Spring Data: Spring's JdbcTemplate knows RowMappers, which are reflected by jOOQ's or
  • -
    +
    diff --git a/jOOQ-website/src/main/resources/manual-3.0.xml b/jOOQ-website/src/main/resources/manual-3.0.xml index 583f353aa7..90a379c4e2 100644 --- a/jOOQ-website/src/main/resources/manual-3.0.xml +++ b/jOOQ-website/src/main/resources/manual-3.0.xml @@ -37,7 +37,7 @@
    The jOOQ User Manual. Multiple Pages - +

    # Overview

    This manual is divided into six main sections:

    @@ -88,12 +88,12 @@

    -
    +
    Preface - +

    jOOQ's reason for being - compared to JPA

    Java and SQL have come a long way. SQL is an "ancient", yet established and well-understood technology. Java is a legacy too, although its platform JVM allows for many new and contemporary languages built on top of it. Yet, after all these years, libraries dealing with the interface between SQL and Java have come and gone, leaving JPA to be a standard that is accepted only with doubts, short of any surviving options. @@ -149,18 +149,18 @@

    SQL was never meant to be abstracted. To be confined in the narrow boundaries of heavy mappers, hiding the beauty and simplicity of relational data. SQL was never meant to be object-oriented. SQL was never meant to be anything other than... SQL!

    -
    +
    Getting started with jOOQ - +

    These chapters contain a quick overview of how to get started with this manual and with jOOQ. While the subsequent chapters contain a lot of reference information, this chapter here just wraps up the essentials.

    -
    +
    How to read this manual - +

    This section helps you correctly interpret this manual in the context of jOOQ.

    @@ -302,28 +302,21 @@ and Maintenance Agreement for more details: http://www.jooq.org/eula The following are code blocks:

    - - - - - -]]> - - + +]]>

    These are useful to provide examples in code. Often, with jOOQ, it is even more useful to compare SQL code with its corresponding Java/jOOQ code. When this is done, the blocks are aligned side-by-side, with SQL usually being on the left, and Java usually being on the right:

    - + - - +

    Code block contents

    @@ -331,13 +324,11 @@ create.selectOne()]]>

    - - - +DSLContext create = DSL.using(connection, SQLDialect.ORACLE);]]>

    Your naming may differ, of course. For instance, you could name the "create" instance "db", instead. @@ -368,16 +359,16 @@ DSLContext create = DSL.using(connection, SQLDialect.ORACLE);]]>

    jOOQ query examples run against the sample database. See the manual's section about to learn more about the sample database.

    -
    +
    The sample database used in this manual - +

    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 language ( +CREATE TABLE language ( id NUMBER(7) NOT NULL PRIMARY KEY, cd CHAR(2) NOT NULL, description VARCHAR2(50) @@ -415,16 +406,16 @@ CREATE TABLE book_to_book_store ( PRIMARY KEY(name, book_id), CONSTRAINT fk_b2bs_book_store FOREIGN KEY (name) REFERENCES book_store (name) ON DELETE CASCADE, CONSTRAINT fk_b2bs_book FOREIGN KEY (book_id) REFERENCES 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

    -
    +
    Different use cases for jOOQ - +

    jOOQ has originally been created as a library for complete abstraction of JDBC and all database interaction. Various best practices that are frequently encountered in pre-existing software products are applied to this library. This includes:

    @@ -453,23 +444,23 @@ CREATE TABLE book_to_book_store (

    The following sections explain about various use cases for using jOOQ in your application.

    -
    +
    jOOQ as a SQL builder - +

    This is the most simple of all use cases, allowing for construction of valid SQL for any database. In this use case, you will not use and probably not even . Instead, you'll use jOOQ to wrap strings, literals and other user-defined objects into an object-oriented, type-safe AST modelling your SQL statements. An example is given here:

    - + .getSQL();]]>

    The SQL string that you can generate as such can then be executed using JDBC directly, using Spring's JdbcTemplate, using Apache DbUtils and many other tools. @@ -481,23 +472,23 @@ String sql = create.select(fieldByName("BOOK","TITLE"), fieldByName("AUTHOR","FI

  • : This section contains a lot of information about creating SQL statements using the jOOQ API
  • : This section contains information useful in particular to those that want to supply , , etc. as plain SQL to jOOQ, rather than through generated artefacts
  • -
    +
    jOOQ as a SQL builder with code generation - +

    In addition to using jOOQ as a , you can also use jOOQ's code generation features in order to compile your SQL statements using a Java compiler against an actual database schema. This adds a lot of power and expressiveness to just simply constructing SQL using custom strings and literals, as you can be sure that all database artefacts actually exist in the database, and that their type is correct. An example is given here:

    - + .getSQL();]]>

    The SQL string that you can generate as such can then be executed using JDBC directly, using Spring's JdbcTemplate, using Apache DbUtils and many other tools. @@ -509,30 +500,30 @@ String sql = create.select(BOOK.TITLE, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)

  • : This section contains a lot of information about creating SQL statements using the jOOQ API
  • : This section contains the necessary information to run jOOQ's code generator against your developer database
  • -
    +
    jOOQ as a SQL executor - +

    Instead of any tool mentioned in the previous chapters, you can also use jOOQ directly to execute your jOOQ-generated SQL statements. This will add a lot of convenience on top of the previously discussed API for typesafe SQL construction, when you can re-use the information from generated classes to fetch records and custom data types. An example is given here:

    -> result = create.select(BOOK.TITLE, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .from(BOOK) .join(AUTHOR) .on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)) .where(BOOK.PUBLISHED_IN.equal(1948)) - .fetch();]]> + .fetch();]]>

    jOOQ doesn't stop here, though! You can execute any SQL with jOOQ. In other words, you can use any other SQL building tool and run the SQL statements with jOOQ. An example is given here:

    - result = create.fetch(sql); // Or execute that SQL with JDBC, fetching the ResultSet with jOOQ: ResultSet rs = connection.createStatement().executeQuery(sql); -Result result = create.fetch(rs);]]> +Result result = create.fetch(rs);]]>

    If you wish to use jOOQ as a SQL executor with (or without) code generation, the following sections of the manual will be of interest to you: @@ -552,17 +543,17 @@ Result result = create.fetch(rs);]]>

  • : This section contains a lot of information about executing SQL statements using the jOOQ API
  • : This section contains some useful information about the various ways of fetching data with jOOQ
  • -
    +
    jOOQ for CRUD - +

    This is probably the most complete use-case for jOOQ: Use all of jOOQ's features. Apart from jOOQ's fluent API for query construction, jOOQ can also help you execute everyday CRUD operations. An example is given here:

    - +}]]>

    If you wish to use all of jOOQ's features, the following sections of the manual will be of interest to you (including all sub-sections): @@ -586,12 +577,12 @@ for (AuthorRecord author : create.fetch(AUTHOR)) {

  • : This section contains the necessary information to run jOOQ's code generator against your developer database
  • : This section contains a lot of information about executing SQL statements using the jOOQ API
  • -
    +
    jOOQ for PROs - +

    jOOQ isn't just a library that helps you and SQL against your . jOOQ ships with a lot of tools. Here are some of the most important tools shipped with jOOQ:

    @@ -606,32 +597,32 @@ for (AuthorRecord author : create.fetch(AUTHOR)) {

    If you're a power user of your favourite, feature-rich database, jOOQ will help you access all of your database's vendor-specific features, such as OLAP features, stored procedures, user-defined types, vendor-specific SQL, functions, etc. Examples are given throughout this manual.

    -
    +
    Tutorials - +

    Don't have time to read the full manual? Here are a couple of tutorials that will get you into the most essential parts of jOOQ as quick as possible.

    -
    +
    jOOQ in 7 easy steps - +

    This manual section is intended for new users, to help them get a running application with jOOQ, quickly.

    -
    +
    Step 1: Preparation - +

    If you haven't already downloaded it, download jOOQ:
    https://sourceforge.net/projects/jooq/files/Release/ @@ -640,7 +631,7 @@ for (AuthorRecord author : create.fetch(AUTHOR)) {

    Alternatively, you can create a Maven dependency to download jOOQ artefacts:

    - + org.jooq jooq {jooq-version} @@ -654,7 +645,7 @@ for (AuthorRecord author : create.fetch(AUTHOR)) { org.jooq jooq-codegen {jooq-version} -]]> +]]>

    Please refer to the manual's section about to learn how to use jOOQ's code generator with Maven. @@ -668,17 +659,17 @@ for (AuthorRecord author : create.fetch(AUTHOR)) {

    If you don't have a MySQL instance up and running yet, get XAMPP now! XAMPP is a simple installation bundle for Apache, MySQL, PHP and Perl

    -
    +
    Step 2: Your database - +

    We're going to create a database called "guestbook" and a corresponding "posts" table. Connect to MySQL via your command line client and type the following:

    -CREATE DATABASE guestbook; +CREATE DATABASE guestbook; CREATE TABLE `posts` ( `id` bigint(20) NOT NULL, @@ -687,13 +678,12 @@ CREATE TABLE `posts` ( `title` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ); - -
    +
    Step 3: Code generation - +

    In this step, we're going to use jOOQ's command line tools to generate classes that map to the Posts table we just created. More detailed information about how to set up the jOOQ code generator can be found here:
    @@ -703,7 +693,7 @@ CREATE TABLE `posts` ( The easiest way to generate a schema is to copy the jOOQ jar files (there should be 3) and the MySQL Connector jar file to a temporary directory. Then, create a guestbook.xml that looks like this:

    - + @@ -746,7 +736,7 @@ CREATE TABLE `posts` ( C:/workspace/MySQLTest/src -]]> +]]>

    Replace the username with whatever user has the appropriate privileges to query the database meta data. You'll also want to look at the other values and replace as necessary. Here are the two interesting properties:

    @@ -761,15 +751,15 @@ CREATE TABLE `posts` ( Once you have the JAR files and guestbook.xml in your temp directory, type this (use colons instead of semi-colons on UNIX/Linux systems):

    -java -classpath jooq-{jooq-version}.jar;jooq-meta-{jooq-version}.jar;jooq-codegen-{jooq-version}.jar;mysql-connector-java-5.1.18-bin.jar;. +java -classpath jooq-{jooq-version}.jar;jooq-meta-{jooq-version}.jar;jooq-codegen-{jooq-version}.jar;mysql-connector-java-5.1.18-bin.jar;. org.jooq.util.GenerationTool /guestbook.xml - +

    Note the prefix slash before guestbook.xml. Even though it's in our working directory, we need to prepend a slash, as the configuration file is loaded from the classpath. Replace the filenames with your filenames. In this example, jOOQ {jooq-version} is being used. If everything has worked, you should see this in your console output:

    -Nov 1, 2011 7:25:06 PM org.jooq.impl.JooqLogger info +Nov 1, 2011 7:25:06 PM org.jooq.impl.JooqLogger info INFO: Initialising properties : /guestbook.xml Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info INFO: Database parameters @@ -825,19 +815,17 @@ Nov 1, 2011 7:25:08 PM org.jooq.impl.JooqLogger info INFO: Packages fetched : 0 (0 included, 0 excluded) Nov 1, 2011 7:25:08 PM org.jooq.impl.JooqLogger info INFO: GENERATION FINISHED! : Total: 791.688ms, +9.143ms - - -
    +
    Step 4: Connect to your database - +

    Let's just write a vanilla main class in the project containing the generated classes:

    - +}]]>

    This is pretty standard code for establishing a MySQL connection.

    -
    +
    Step 5: Querying - +

    Let's add a simple query:

    - result = create.select().from(POSTS).fetch();]]> + result = create.select().from(POSTS).fetch();]]>

    First get an instance of DSLContext so we can write a simple SELECT query. We pass an instance of the MySQL connection to DSL. Note that the DSLContext doesn't close the connection. We'll have to do that ourselves. @@ -888,29 +876,29 @@ Result result = create.select().from(POSTS).fetch();]]>

    We then use jOOQ's DSL to return an instance of Result. We'll be using this result in the next step.

    -
    +
    Step 6: Iterating - +

    After the line where we retrieve the results, let's iterate over the results and print out the data:

    - +}]]>

    The full program should now look like this:

    - -
    +}]]>
    Step 7: Explore! - +

    jOOQ has grown to be a comprehensive SQL library. For more information, please consider the documentation:
    http://www.jooq.org/learn.php @@ -983,37 +970,37 @@ public class Main { This tutorial is the courtesy of Ikai Lan. See the original source here:
    http://ikaisays.com/2011/11/01/getting-started-with-jooq-a-tutorial/

    -
    +
    Using jOOQ in modern IDEs - +

    Feel free to contribute a tutorial!

    -
    +
    Using jOOQ with Spring - +

    Feel free to contribute a tutorial!

    -
    +
    A simple web application with jOOQ - +

    Feel free to contribute a tutorial!

    -
    +
    jOOQ and Scala - +

    As any other library, jOOQ can be easily used in Scala, taking advantage of the many Scala language features such as for example:

    @@ -1036,7 +1023,7 @@ public class Main { A short example jOOQ application in Scala might look like this:

    - +}]]>

    For more details about jOOQ's Scala integration, please refer to the manual's section about .

    -
    +
    Dependencies - +

    Dependencies are a big hassle in modern software. Many libraries depend on other, non-JDK library parts that come in different, incompatible versions, potentially causing trouble in your runtime environment. jOOQ has no external dependencies on any third-party libraries.

    @@ -1097,12 +1084,12 @@ object Test { //
  • Small libraries with compatible licenses are incorporated into jOOQ. These include jOOR, jOOU, parts of OpenCSV, json simple, parts of commons-lang
  • javax.persistence and javax.validation will be needed if you activate the relevant
  • -
    +
    Build your own - +

    In order to build jOOQ yourself, please download the sources from https://github.com/jOOQ/jOOQ and use Maven to build jOOQ, preferably in Eclipse. jOOQ requires Java 6+ to compile and run.

    @@ -1126,12 +1113,12 @@ object Test { // -
    +
    jOOQ and backwards-compatibility - +

    jOOQ follows the rules of semantic versioning according to http://semver.org quite strictly. Those rules impose a versioning scheme [X].[Y].[Z] that can be summarised as follows:

    @@ -1159,14 +1146,14 @@ object Test { //

    jOOQ's DSL interfaces should not be implemented by client code! Extend only those extension points that are explicitly documented as "extendable" (e.g. )

    -
    +
    SQL building - +

    SQL is a declarative language that is hard to integrate into procedural, object-oriented, functional or any other type of programming languages. jOOQ's philosophy is to give SQL the credit it deserves and integrate SQL itself as an "internal domain specific language" directly into Java.

    @@ -1176,7 +1163,7 @@ object Test { //

    This section explains all about the various syntax elements involved with jOOQ's SQL building capabilities. For a complete overview of all syntax elements, please refer to the manual's section about

    -
    +
    @@ -1185,7 +1172,7 @@ object Test { //
    The DSL type - +

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

    @@ -1203,21 +1190,20 @@ object Test { // With jOOQ 2.0, static factory methods have been introduced in order to make client code look more like SQL. Ideally, when working with jOOQ, you will simply static import all methods from the DSL class:

    -import static org.jooq.impl.DSL.*; +import static org.jooq.impl.DSL.*;

    Note, that when working with Eclipse, you could also add the DSL to your favourites. This will allow to access functions even more fluently:

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

    There are a couple of subclasses for the general DSL. Each SQL dialect has its own dialect-specific DSL. For instance, if you're only using the MySQL dialect, you can choose to reference the MySQLDSL instead of the standard DSL:

    @@ -1228,7 +1214,7 @@ DSL.concat(DSL.trim(FIRST_NAME), DSL.trim(LAST_NAME));
  • MySQL's encryption functions
  • PL/SQL constructs, pgplsql, or any other dialect's ROUTINE-language (maybe in the future)
  • -
    +
    @@ -1244,7 +1230,7 @@ DSL.concat(DSL.trim(FIRST_NAME), DSL.trim(LAST_NAME));
    The DSLContext class - +

    DSLContext references a , an object that configures jOOQ's behaviour when executing queries (see for more details). Unlike the static DSL, the DSLContext allow for creating that are already "configured" and ready for execution.

    @@ -1254,11 +1240,11 @@ DSL.concat(DSL.trim(FIRST_NAME), DSL.trim(LAST_NAME)); The DSLContext object can be created fluently from the :

    - +DSLContext create = DSL.using(connection, dialect);]]>

    If you do not have a reference to a pre-existing Configuration object (e.g. created from ), the various overloaded DSL.using() methods will create one for you. @@ -1285,32 +1271,31 @@ DSLContext create = DSL.using(connection, dialect);]]>

    Wrapping a Configuration object, a DSLContext can construct , for later . An example is given here:

    - select = create.selectOne(); // Using the internally referenced Configuration, the select statement can now be executed: -Result result = select.fetch();]]> +Result result = select.fetch();]]>

    Note that you do not need to keep a reference to a DSLContext. You may as well inline your local variable, and fluently execute a SQL statement as such:

    - result = DSL.using(connection, dialect) .select() .from(BOOK) .where(BOOK.TITLE.like("Animal%")) - .fetch();]]> -
    + .fetch();]]>
    SQL Dialect - +

    While jOOQ tries to represent the SQL standard as much as possible, many features are vendor-specific to a given database and to its "SQL dialect". jOOQ models this using the enum type.

    @@ -1320,27 +1305,27 @@ DSL.using(connection, dialect)

    Some parts of the jOOQ API are officially supported only by a given subset of the supported SQL dialects. For instance, the , which is supported by the Oracle and CUBRID databases, is annotated with a annotation, as such:

    -CONNECT BY clause to the query */ @Support({ SQLDialect.CUBRID, SQLDialect.ORACLE }) -SelectConnectByConditionStep connectBy(Condition condition);]]> +SelectConnectByConditionStep connectBy(Condition condition);]]>

    jOOQ API methods which are not annotated with the annotation, or which are annotated with the Support annotation, but without any SQL dialects can be safely used in all SQL dialects. An example for this is the factory method:

    - select(Field... fields);]]> +SelectSelectStep select(Field... fields);]]>

    jOOQ's SQL clause simulation capabilities

    The aforementioned Support annotation does not only designate, which databases natively support a feature. It also indicates that a feature is simulated by jOOQ for some databases lacking this feature. An example of this is the , a predicate syntax defined by SQL:1999 and implemented only by H2, HSQLDB, and Postgres:

    - +

    Nevertheless, the IS DISTINCT FROM predicate is supported by jOOQ in all dialects, as its semantics can be expressed with an equivalent . For more details, see the manual's section about the . @@ -1360,12 +1345,12 @@ SelectSelectStep select(Field... fields);]]>

    jOOQ has a historic affinity to Oracle's SQL extensions. If something is supported in Oracle SQL, it has a high probability of making it into the jOOQ API

    -
    +
    Connection vs. DataSource - +

    Interact with JDBC Connections

    While you can use jOOQ for only, you can also run queries against a JDBC . Internally, jOOQ creates or objects from such a Connection, in order to execute statements. The normal operation mode is to provide a with a JDBC Connection, whose lifecycle you will control yourself. This means that jOOQ will not actively close connections, rollback or commit transactions. @@ -1387,24 +1372,24 @@ SelectSelectStep select(Field... fields);]]> If your specific environment works differently from any of the above approaches, you can inject your own custom implementation of a ConnectionProvider into jOOQ. This is the API contract you have to fulfil:

    - +}]]>

    Note that acquire() should always return the same Connection until this connection is returned via release()

    -
    +
    Custom data - +

    In advanced use cases of integrating your application with jOOQ, you may want to put custom data into your , which you can then access from your...

    @@ -1418,7 +1403,7 @@ SelectSelectStep select(Field... fields);]]> Here is an example of how to use the custom data API. Let's assume that you have written an , that prevents INSERT statements, when a given flag is set to true:

    - +}]]>

    See the manual's section about to learn more about how to implement an ExecuteListener.

    @@ -1442,7 +1427,7 @@ public class NoInsertListener extends DefaultExecuteListener { Now, the above listener can be added to your , but you will also need to pass the flag to the Configuration, in order for the listener to work:

    - +}]]>

    Using the data() methods, you can store and retrieve custom data in your Configurations.

    -
    +
    Custom ExecuteListeners - +

    ExecuteListeners are a useful tool to...

    @@ -1491,7 +1476,7 @@ catch (DataAccessException expected) { ExecuteListeners are hooked into your by returning them from an :

    - +);]]>

    See the manual's section about to see examples of such listener implementations.

    -
    +
    Custom Settings - +

    The jOOQ Configuration 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 Configuration in several ways:

    @@ -1524,9 +1509,9 @@ configuration.set(

    For example, if you want to indicate to jOOQ, that it should inline all bind variables, and execute static instead of binding its variables to , you can do so by creating the following DSLContext:

    - +DSLContext create = DSL.using(connection, dialect, settings);]]>

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

    @@ -1545,12 +1530,12 @@ DSLContext create = DSL.using(connection, dialect, settings);]]> Please refer to the jOOQ runtime configuration XSD for more details:
    http://www.jooq.org/xsd/jooq-runtime-{runtime-xsd-version}.xsd

    -
    +
    Runtime schema and table mapping - +

    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. @@ -1570,7 +1555,7 @@ DSLContext create = DSL.using(connection, dialect, settings);]]> 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 Configuration's with. Take the following example:

    -Settings settings = new Settings() +Settings settings = new Settings() .withRenderMapping(new RenderMapping() .withSchemata( new MappedSchema().withInput("DEV") @@ -1580,13 +1565,13 @@ DSLContext create = DSL.using(connection, dialect, settings);]]> DSLContext create = DSL.using(connection, SQLDialect.ORACLE, settings); // Run queries with the "mapped" Configuration -create.selectFrom(AUTHOR).fetch(); +create.selectFrom(AUTHOR).fetch();

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

    -SELECT * FROM MY_BOOK_WORLD.AUTHOR +SELECT * FROM MY_BOOK_WORLD.AUTHOR

    Even if AUTHOR was generated from DEV.

    @@ -1596,7 +1581,7 @@ create.selectFrom(AUTHOR).fetch(); 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):

    - + @@ -1609,13 +1594,13 @@ create.selectFrom(AUTHOR).fetch(); -]]> +]]>

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

    -Settings settings = JAXB.unmarshal(new File("jooq-runtime.xml"), Settings.class); +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 Configuration. @@ -1628,21 +1613,21 @@ create.selectFrom(AUTHOR).fetch();

    -Settings settings = new Settings() +Settings settings = new Settings() .withRenderSchema(false); // Add the settings to the Configuration DSLContext create = DSL.using(connection, SQLDialect.ORACLE, settings); // Run queries that omit rendering schema names -create.selectFrom(AUTHOR).fetch(); +create.selectFrom(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.AUTHOR to something MY_BOOK_WORLD.MY_APP__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() +Settings settings = new Settings() .withRenderMapping(new RenderMapping() .withSchemata( new MappedSchema().withInput("DEV") @@ -1655,13 +1640,13 @@ create.selectFrom(AUTHOR).fetch(); DSLContext create = DSL.using(connection, SQLDialect.ORACLE, settings); // Run queries with the "mapped" configuration -create.selectFrom(AUTHOR).fetch(); +create.selectFrom(AUTHOR).fetch();

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

    -SELECT * FROM MY_BOOK_WORLD.MY_APP__AUTHOR +SELECT * FROM MY_BOOK_WORLD.MY_APP__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! @@ -1671,23 +1656,23 @@ create.selectFrom(AUTHOR).fetch();

    Note that the manual's section about explains how you can hard-wire your schema mappings at code generation time

    -
    +
    SQL Statements - +

    jOOQ currently supports 6 types of SQL statements. All of these statements are constructed from a DSLContext instance with an optional . If supplied with a Connection or DataSource, they can be executed. Depending on the , executed queries can return results.

    -
    +
    jOOQ's DSL and model API - +

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

    @@ -1695,22 +1680,21 @@ create.selectFrom(AUTHOR).fetch(); Here is an example to illustrate what that means:

    - 1920 AND a.first_name = 'Paulo' - ORDER BY b.title]]> - result = + ORDER BY b.title]]> result = create.select() .from(AUTHOR.as("a")) .join(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();]]> + .fetch();]]>

    We'll see how the aliasing works later in the section about @@ -1721,16 +1705,16 @@ create.select() Many other frameworks have similar APIs with similar feature sets. Yet, what makes jOOQ special is its informal modelling a unified SQL dialect suitable for many vendor-specific dialects, and implementing that BNF notation as a hierarchy of interfaces in Java. This concept is extremely powerful, when with syntax completion. Not only can you code much faster, your SQL code will be compile-checked to a certain extent. An example of a DSL query equivalent to the previous one is given here:

    - result = create.select() .from(AUTHOR) .join(BOOK).on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)) - .fetch();]]> + .fetch();]]>

    Unlike other, simpler frameworks that use "fluent APIs" or "method chaining", jOOQ's BNF-based interface hierarchy will not allow bad query syntax. The following will not compile, for instance:

    - result = create.select() .join(BOOK).on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)) // ^^^^ "join" is not possible here @@ -1760,14 +1744,14 @@ Result result = create.select() .where(AUTHOR.ID.in(select(BOOK.AUTHOR_ID, BOOK.ID).from(BOOK))) // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // AUTHOR.ID is of degree 1 but subselect returns Record2 - .fetch();]]> + .fetch();]]>

    History of SQL building and incremental query building (a.k.a. the model API)

    Historically, jOOQ started out as an object-oriented SQL builder library like any other. This meant that all queries and their syntactic components were modeled as so-called , which delegate and to child components. This part of the API will be referred to as the model API (or non-DSL API), which is still maintained and used internally by jOOQ for incremental query building. An example of incremental query building is given here:

    - query = create.selectQuery(); query.addFrom(AUTHOR); @@ -1776,25 +1760,25 @@ if (join) { query.addJoin(BOOK, BOOK.AUTHOR_ID.equal(AUTHOR.ID)); } -Result result = query.fetch();]]> +Result result = query.fetch();]]>

    This query is equivalent to the one shown before using the DSL syntax. In fact, internally, the DSL API constructs precisely this SelectQuery object. Note, that you can always access the SelectQuery object to switch between DSL and model APIs:

    - select = create.select().from(AUTHOR); // Add the JOIN clause on the internal QueryObject representation SelectQuery query = select.getQuery(); -query.addJoin(BOOK, BOOK.AUTHOR_ID.equal(AUTHOR.ID));]]> +query.addJoin(BOOK, BOOK.AUTHOR_ID.equal(AUTHOR.ID));]]>

    Mutability

    Note, that for historic reasons, the DSL API mixes mutable and immutable behaviour with respect to the internal representation of the being constructed. While creating , (such as functions) assumes immutable behaviour, creating does not. In other words, the following can be said:

    - s3 = s1.from(AUTHOR); // The following can be said s1 == s2; // The internal object is always the same -s2 == s3; // The internal object is always the same]]> +s2 == s3; // The internal object is always the same]]>

    On the other hand, beware that you can always extract and modify from any QueryPart.

    -
    +
    The SELECT statement - +

    When you don't just perform (i.e. SELECT * FROM your_table WHERE ID = ?), you're usually generating new record 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:

    SELECT from a complex table expression

    - + - - +

    Details about the various clauses of this query will be provided in subsequent sections. @@ -1875,14 +1858,14 @@ create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, count()) A very similar, but limited API is available, if you want to select from single physical tables in order to retrieve . The decision, which type of select to create is already made at the very first step, when you create the SELECT statement with the DSL or DSLContext types:

    - SelectWhereStep selectFrom(Table table);]]> + SelectWhereStep selectFrom(Table 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:

    - + .fetchAny();]]>

    The "reduced" SELECT API is limited in the way that it skips DSL access to any of these clauses: @@ -1894,41 +1877,39 @@ create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, count())

    In most parts of this manual, it is assumed that you do not use the "reduced" SELECT API. For more information about the simple SELECT API, see the manual's section about .

    -
    +
    The SELECT clause - +

    The SELECT clause lets you project your own record types, referencing table fields, functions, arithmetic expressions, etc. The DSL type provides several methods for expressing a SELECT clause:

    - + - s1 = create.select(BOOK.ID, BOOK.TITLE); Select s2 = create.select(BOOK.ID, trim(BOOK.TITLE));]]> - +

    Some commonly used projections can be easily created using convenience methods:

    - + - select1 = create.selectCount(); Select select2 = create.selectZero(); Select select2 = create.selectOne();]]> - +

    See more details about functions and expressions in the manual's section about @@ -1939,17 +1920,16 @@ Select select2 = create.selectOne();]]> The DISTINCT keyword can be included in the method name, constructing a SELECT clause

    - - - select1 = create.selectDistinct(BOOK.TITLE);]]> - + + select1 = create.selectDistinct(BOOK.TITLE);]]> +

    SELECT *

    jOOQ does not explicitly support the asterisk operator in projections. However, you can omit the projection as in these examples:

    - +create.select().from(tableByName("BOOK"));]]>

    Typesafe projections with degree up to {max-row-degree}

    Since jOOQ 3.0, and up to degree {max-row-degree} are now generically typesafe. This is reflected by an overloaded SELECT (and SELECT DISTINCT) API in both DSL and DSLContext. An extract from the DSL type:

    - select(Collection> fields); public static SelectSelectStep select(Field... fields); @@ -1972,36 +1952,35 @@ public static SelectSelectStep select(Field... fields); public static SelectSelectStep> select(Field field1); public static SelectSelectStep> select(Field field1, Field field2); public static SelectSelectStep> select(Field field1, Field field2, Field field3); -// [...]]]> +// [...]]]>

    Since the generic R type is bound to some , the associated T type information can be used in various other contexts, e.g. the . Such a SELECT statement can be assigned typesafely:

    -> s1 = create.select(BOOK.ID, BOOK.TITLE); -Select> s2 = create.select(BOOK.ID, trim(BOOK.TITLE));]]> +> s1 = create.select(BOOK.ID, BOOK.TITLE); +Select> s2 = create.select(BOOK.ID, trim(BOOK.TITLE));]]>

    For more information about typesafe record types with degree up to {max-row-degree}, see the manual's section about .

    -
    +
    The FROM clause - +

    The SQL FROM clause allows for specifying any number of to select data from. The following are examples of how to form normal FROM clauses:

    - + - - +

    Read more about aliasing in the manual's section about . @@ -2012,12 +1991,11 @@ create.selectOne().from(BOOK.as("b"), AUTHOR.as("a"));]]> Apart from simple tables, you can pass any arbitrary to the jOOQ FROM clause. This may include in Oracle:

    - + - - +

    Note, in order to access the DbmsXplan package, you can use the to generate Oracle's SYS schema. @@ -2029,22 +2007,21 @@ FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(null, null, 'ALLSTATS'));]]> In many SQL dialects, FROM is a mandatory clause, in some it isn't. jOOQ allows you to omit the FROM clause, returning just one record. An example:

    - + - - +

    Read more about dual or dummy tables in the manual's section about . The following are examples of how to form normal FROM clauses:

    -
    +
    The JOIN clause - +

    jOOQ supports many different types of standard SQL JOIN operations:

    @@ -2063,7 +2040,7 @@ DSL.using(SQLDialect.POSTGRES).selectOne().getSQL();]]> All of these JOIN methods can be called on types, or directly after the FROM clause for convenience. The following example joins AUTHOR and BOOK

    - result = create.select() @@ -2076,27 +2053,26 @@ Result result = create.select() .from(AUTHOR) .join(BOOK) .on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)) - .fetch();]]> + .fetch();]]>

    The two syntaxes will produce the same SQL statement. However, calling "join" on objects allows for more powerful, nested JOIN expressions (if you can handle the parentheses):

    - + - + .on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)));]]>
    • See the section about to learn more about the many ways to create objects in jOOQ.
    • @@ -2108,13 +2084,12 @@ create.select() Surprisingly, the SQL standard does not allow to formally JOIN on well-known foreign key relationship information. Naturally, when you join BOOK to AUTHOR, you will want to do that based on the BOOK.AUTHOR_ID foreign key to AUTHOR.ID primary key relation. Not being able to do this in SQL leads to a lot of repetitive code, re-writing the same JOIN predicate again and again - especially, when your foreign keys contain more than one column. With jOOQ, when you use , you can use foreign key constraint information in JOIN expressions as such:

      - + - + .join(BOOK).onKey();]]>

      In case of ambiguity, you can also supply field references for your foreign keys, or the generated foreign key reference to the onKey() method. @@ -2128,137 +2103,130 @@ JOIN BOOK ON BOOK.AUTHOR_ID = AUTHOR.ID]]> Most often, you will provide jOOQ with JOIN conditions in the JOIN .. ON clause. SQL supports a different means of specifying how two tables are to be joined. This is the JOIN .. USING clause. Instead of a condition, you supply a set of fields whose names are common to both tables to the left and right of a JOIN operation. This can be useful when your database schema has a high degree of relational normalisation. An example:

      - + - + .join(BOOK).using(AUTHOR.AUTHOR_ID);]]>

      In schemas with high degrees of normalisation, you may also choose to use NATURAL JOIN, which takes no JOIN arguments as it joins using all fields that are common to the table expressions to the left and to the right of the JOIN operator. An example:

      - + - + .naturalJoin(BOOK);]]>

      Oracle's partitioned OUTER JOIN

      Oracle SQL ships with a special syntax available for OUTER JOIN clauses. According to the Oracle documentation about partitioned outer joins this can be used to fill gaps for simplified analytical calculations. jOOQ only supports putting the PARTITION BY clause to the right of the OUTER JOIN clause. The following example will create at least one record per AUTHOR and per existing value in BOOK.PUBLISHED_IN, regardless if an AUTHOR has actually published a book in that year.

      - + - + .on(BOOK.AUTHOR_ID.equal(AUTHOR.ID));]]> - +
    The WHERE clause - +

    The WHERE clause can be used for JOIN or filter predicates, in order to restrict the data returned by the supplied to the previously specified and . Here is an example:

    - + - + .and(BOOK.TITLE.equal("1984"));]]>

    The above syntax is convenience provided by jOOQ, allowing you to connect the supplied in the WHERE clause with another condition using an AND operator. You can of course also create a more complex condition and supply that to the WHERE clause directly (observe the different placing of parentheses). The results will be the same:

    - + - + BOOK.TITLE.equal("1984")));]]>

    You will find more information about creating later in the manual.

    -
    +
    The CONNECT BY clause - +

    The Oracle database knows a very succinct syntax for creating hierarchical queries: the CONNECT BY clause, which is fully supported by jOOQ, including all related functions and pseudo-columns. A more or less formal definition of this clause is given here:

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

    An example for an iterative query, iterating through values between 1 and 5 is this:

    - + - + .connectBy(level().lessOrEqual(5));]]>

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

    - + - - +

    The output might then look like this

    -+------------------------------------------------+ ++------------------------------------------------+ |substring | +------------------------------------------------+ |C: | @@ -2268,7 +2236,7 @@ ORDER BY 1]]> |C:/eclipse/eclipse.exe | +------------------------------------------------+ |...21 record(s) truncated... - +

    Some of the supported functions and pseudo-columns are these (available from the ): @@ -2292,38 +2260,36 @@ ORDER BY 1]]> The Oracle database allows for specifying a SIBLINGS keyword in the . Instead of ordering the overall result, this will only order siblings among each other, keeping the hierarchy intact. An example is given here:

    - + - - + -
    +
    The GROUP BY clause - +

    GROUP BY can be used to create unique groups of data, to form aggregations, to remove duplicates and for other reasons. It will transform your previously defined , and return only one record per unique group as specified in this clause. For instance, you can group books by BOOK.AUTHOR_ID:

    - + - + .groupBy(BOOK.AUTHOR_ID);]]>

    The above example counts all books per author. @@ -2337,13 +2303,12 @@ GROUP BY AUTHOR_ID]]> MySQL has a peculiar way of not adhering to this standard behaviour. This is documented in the MySQL manual. In short, with MySQL, you can also project any other field that is not part of the GROUP BY clause. The projected values will just be arbitrary values from within the group. You cannot rely on any ordering. For example:

    - + - + .groupBy(AUTHOR_ID);]]>

    This will return an arbitrary title per author. jOOQ supports this syntax, as jOOQ is not doing any checks internally, about the consistence of tables/fields/functions that you provide it. @@ -2354,68 +2319,64 @@ GROUP BY AUTHOR_ID]]> jOOQ supports empty GROUP BY () clause as well. This will result in that return only one record.

    - + - + .groupBy();]]>

    ROLLUP(), CUBE() and GROUPING SETS()

    Some databases support the SQL standard grouping functions and some extensions thereof. See the manual's section about for more details.

    -
    +
    The HAVING clause - +

    The HAVING clause is commonly used to further restrict data resulting from a previously issued . An example, selecting only those authors that have written at least two books:

    - + = 2]]> -= 2]]> + .having(count().greaterOrEqual(2));]]>

    According to the SQL standard, you may omit the GROUP BY clause and still issue a HAVING clause. This will implicitly GROUP BY (). jOOQ also supports this syntax. The following example selects one record, only if there are at least 4 books in the books table:

    - + = 4]]> -= 4]]> + .having(count().greaterOrEqual(4));]]> -
    +
    The ORDER BY clause - +

    Databases are allowed to return data in any arbitrary order, unless you explicitly declare that order in the ORDER BY clause. In jOOQ, this is straight-forward:

    - + - + .orderBy(BOOK.AUTHOR_ID.asc(), BOOK.TITLE.desc());]]>

    Any jOOQ can be transformed into an by calling the asc() and desc() methods. @@ -2426,13 +2387,12 @@ ORDER BY AUTHOR_ID ASC, TITLE DESC]]> The SQL standard allows for specifying integer literals (, not !) to reference column indexes from the projection (). This may be useful if you do not want to repeat a lengthy expression, by which you want to order - although most databases also allow for referencing in the ORDER BY clause. An example of this is given here:

    - + - + .orderBy(one().asc(), inline(2).desc());]]>

    Note, how one() is used as a convenience short-cut for inline(1) @@ -2443,87 +2403,84 @@ ORDER BY 1 ASC, 2 DESC]]> A few databases support the SQL standard "null ordering" clause in sort specification lists, to define whether NULL values should come first or last in an ordered result.

    - + - + BOOK.CO_AUTHOR_ID.asc().nullsLast());]]>

    If your database doesn't support this syntax, jOOQ simulates it using a as follows

    - + - + BOOK.CO_AUTHOR_ID.asc().nullsLast());]]>

    Ordering using CASE expressions

    Using in SQL ORDER BY clauses is a common pattern, if you want to introduce some sort indirection / sort mapping into your queries. As with SQL, you can add any type of into your ORDER BY clause. For instance, if you have two favourite books that you always want to appear on top, you could write:

    - + - + .otherwise(2).asc());]]>

    But writing these things can become quite verbose. jOOQ supports a convenient syntax for specifying sort mappings. The same query can be written in jOOQ as such:

    - + .orderBy(BOOK.TITLE.sortAsc("1984", "Animal Farm"));]]>

    More complex sort indirections can be provided using a Map:

    -() {{ put("1984", 1); put("Animal Farm", 13); put("The jOOQ book", 10); - }}));]]> + }}));]]>

    Of course, you can combine this feature with the previously discussed NULLS FIRST / NULLS LAST feature. So, if in fact these two books are the ones you like least, you can put all NULLS FIRST (all the other books):

    - + .orderBy(BOOK.TITLE.sortAsc("1984", "Animal Farm").nullsFirst());]]>

    jOOQ's understanding of SELECT .. ORDER BY

    @@ -2535,23 +2492,23 @@ ORDER BY CASE TITLE

    jOOQ also supports Oracle's SIBLINGS keyword to be used with ORDER BY clauses for

    -
    +
    The LIMIT .. OFFSET clause - +

    While being extremely useful for every application that does paging, or just to limit result sets to reasonable sizes, this clause is not yet part of any SQL standard (up until SQL:2008). Hence, there exist a variety of possible implementations in various SQL dialects, concerning this limit clause. jOOQ chose to implement the LIMIT .. OFFSET clause as understood and supported by MySQL, H2, HSQLDB, Postgres, and SQLite. Here is an example of how to apply limits with jOOQ:

    - +

    This will limit the result to 1 books starting with the 2nd book (starting at offset 0!). limit() is supported in all dialects, offset() in all but Sybase ASE, which has no reasonable means to simulate it. This is how jOOQ simulates the above query in various SQL dialects:

    - 1 AND ROWNUM_98843777 <= 3 -]]> +]]>

    As you can see, jOOQ will take care of the incredibly painful ROW_NUMBER() OVER() (or ROWNUM for Oracle) filtering in subselects for you, you'll just have to write limit(1).offset(2) in any dialect. @@ -2596,39 +2553,37 @@ AND ROWNUM_98843777 <= 3

    As can be seen in the above example, writing correct SQL can be quite tricky, depending on the SQL dialect. For instance, with SQL Server, you cannot have an ORDER BY clause in a subquery, unless you also have a TOP clause. This is illustrated by the fact that jOOQ renders a TOP 100 PERCENT clause for you. The same applies to the fact that ROW_NUMBER() OVER() needs an ORDER BY windowing clause, even if you don't provide one to the jOOQ query. By default, jOOQ adds ordering by the first column of your projection.

    -
    +
    The FOR UPDATE clause - +

    For inter-process synchronisation and other reasons, you may choose to use the SELECT .. FOR UPDATE clause to indicate to the database, that a set of cells or records should be locked by a given transaction for subsequent updates. With jOOQ, this can be achieved as such:

    - + - + .forUpdate();]]>

    The above example will produce a record-lock, locking the whole record for updates. Some databases also support cell-locks using FOR UPDATE OF ..

    - + - + .forUpdate().of(BOOK.TITLE);]]>

    Oracle goes a bit further and also allows to specify the actual locking behaviour. It features these additional clauses, which are all supported by jOOQ: @@ -2642,15 +2597,15 @@ FOR UPDATE OF TITLE]]> With jOOQ, you can use those Oracle extensions as such:

    - +create.select().from(BOOK).where(BOOK.ID.equal(3)).forUpdate().skipLocked();]]>

    FOR UPDATE in CUBRID and SQL Server

    The SQL standard specifies a FOR UPDATE clause to be applicable for cursors. Most databases interpret this as being applicable for all SELECT statements. An exception to this rule are the CUBRID and SQL Server databases, that do not allow for any FOR UPDATE clause in a regular SQL SELECT statement. jOOQ simulates the FOR UPDATE behaviour, by locking record by record with JDBC. JDBC allows for specifying the flags TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE for any statement, and then using ResultSet.updateXXX() methods to produce a cell-lock / row-lock. Here's a simplified example in JDBC:

    - +}]]>

    The main drawback of this approach is the fact that the database has to maintain a scrollable cursor, whose records are locked one by one. This can cause a major risk of deadlocks or race conditions if the JDBC driver can recover from the unsuccessful locking, if two Java threads execute the following statements:

    - +SELECT * FROM author ORDER BY id DESC;]]>

    So use this technique with care, possibly only ever locking single rows! @@ -2687,12 +2642,12 @@ SELECT * FROM author ORDER BY id DESC;]]>

    Note, that jOOQ also supports optimistic locking, if you're doing simple CRUD. This is documented in the section's manual about .

    -
    +
    UNION, INTERSECTION and EXCEPT - +

    SQL allows to perform set operations as understood in standard set theory on result sets. These operations include unions, intersections, subtractions. For two subselects to be combinable by such a set operator, each subselect must return a of the same degree and type.

    @@ -2702,13 +2657,12 @@ SELECT * FROM author ORDER BY id DESC;]]> These operators combine two results into one. While UNION removes all duplicate records resulting from this combination, UNION ALL leaves subselect results as they are. Typically, you should prefer UNION ALL over UNION, if you don't really need to remove duplicates. The following example shows how to use such a UNION operation in jOOQ.

    - + - +create.selectFrom(BOOK).where(BOOK.ID.equal(5)));]]>

    INTERSECT [ ALL ] and EXCEPT [ ALL ]

    @@ -2720,24 +2674,23 @@ create.selectFrom(BOOK).where(BOOK.ID.equal(5)));]]> As previously mentioned in the manual's section about the , jOOQ has slightly changed the semantics of these set operators. While in SQL, a subselect may not contain any or (unless you wrap the subselect into a ), jOOQ allows you to do so. In order to select both the youngest and the oldest author from the database, you can issue the following statement with jOOQ (rendered to the MySQL dialect):

    - + - + .orderBy(AUTHOR.DATE_OF_BIRTH.desc()).limit(1));]]>

    Projection typesafety for degrees between 1 and {max-row-degree}

    Two subselects that are combined by a set operator are required to be of the same degree and, in most databases, also of the same type. jOOQ 3.0's introduction of helps compile-checking these constraints:

    -> s1 = select(BOOK.ID, BOOK.TITLE).from(BOOK); Select> s2 = selectOne(); Select> s3 = select(one(), zero()); @@ -2746,46 +2699,44 @@ Select> s4 = select(one(), inline("abc")); // Let's try to combine them: s1.union(s2); // Doesn't compile because of a degree mismatch. Expected: Record2<...>, got: Record1<...> s1.union(s3); // Doesn't compile because of a type mismatch. Expected: , got: -s1.union(s4); // OK. The two Record[N] types match]]> -
    +s1.union(s4); // OK. The two Record[N] types match]]>
    Oracle-style hints - +

    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 AUTHOR +SELECT /*+ALL_ROWS*/ FIRST_NAME, LAST_NAME + FROM AUTHOR

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

    -create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) +create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .hint("/*+ALL_ROWS*/") - .from(AUTHOR); + .from(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. This can be useful in other databases too, such as MySQL, for instance:

    - + - - -
    + +
    Lexical and logical SELECT clause order - +

    SQL has a lexical and a logical order of SELECT clauses. The lexical order of SELECT clauses is inspired by the English language. As SQL statements are commands for the database, it is natural to express a statement in an imperative tense, such as "SELECT this and that!".

    @@ -2838,7 +2789,7 @@ FROM table1

    A LINQ example:

    - +Select p]]>

    A SLICK example:

    - +} yield (c.name, c.price)]]>

    While this looks like a good idea at first, it only complicates translation to more advanced SQL statements while impairing readability for those users that are used to writing SQL. jOOQ is designed to look just like SQL. This is specifically true for SLICK, which not only changed the SELECT clause order, but also heavily "integrated" SQL clauses with the Scala language. @@ -2867,48 +2818,46 @@ val q = for {

    For these reasons, the jOOQ DSL API is modelled in SQL's lexical order.

    -
    +
    The INSERT statement - +

    The INSERT statement is used to insert new records into a database table. Records can either be supplied using a VALUES() constructor, or a SELECT statement. jOOQ supports both types of INSERT statements. An example of an INSERT statement using a VALUES() constructor is given here:

    - + INSERT INTO AUTHOR (ID, FIRST_NAME, LAST_NAME) -VALUES (100, 'Hermann', 'Hesse'); -create.insertInto(AUTHOR, +VALUES (100, 'Hermann', 'Hesse');create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) - .values(100, "Hermann", "Hesse"); + .values(100, "Hermann", "Hesse");

    Note that for explicit degrees up to {max-row-degree}, the VALUES() constructor provides additional typesafety. The following example illustrates this:

    - step = + step = create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME); step.values("A", "B", "C"); - // ^^^ Doesn't compile, the expected type is Integer]]> + // ^^^ Doesn't compile, the expected type is Integer]]>

    INSERT multiple rows with the VALUES() constructor

    The SQL standard specifies that multiple rows can be supplied to the VALUES() constructor in an INSERT statement. Here's an example of a multi-record INSERT

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

    jOOQ tries to stay close to actual SQL. In detail, however, Java's expressiveness is limited. That's why the values() clause is repeated for every record in multi-record inserts. @@ -2917,30 +2866,29 @@ VALUES (100, 'Hermann', 'Hesse'), Some RDBMS do not support inserting several records in a single statement. In those cases, jOOQ simulates multi-record INSERTs using the following SQL:

    - + INSERT INTO AUTHOR (ID, FIRST_NAME, LAST_NAME) SELECT 100, 'Hermann', 'Hesse' FROM DUAL UNION ALL -SELECT 101, 'Alfred', 'Döblin' FROM DUAL; -create.insertInto(AUTHOR, +SELECT 101, 'Alfred', 'Döblin' FROM DUAL;create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .values(100, "Hermann", "Hesse") .values(101, "Alfred", "Döblin"); - +

    INSERT using jOOQ's alternative syntax

    MySQL (and some other RDBMS) allow for using a non-SQL-standard, 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(AUTHOR) +create.insertInto(AUTHOR) .set(AUTHOR.ID, 100) .set(AUTHOR.FIRST_NAME, "Hermann") .set(AUTHOR.LAST_NAME, "Hesse") .newRecord() .set(AUTHOR.ID, 101) .set(AUTHOR.FIRST_NAME, "Alfred") - .set(AUTHOR.LAST_NAME, "Döblin"); + .set(AUTHOR.LAST_NAME, "Döblin");

    As you can see, this syntax is a bit more verbose, but also more readable, as every field can be matched with its value. Internally, the two syntaxes are strictly equivalent. @@ -2951,12 +2899,12 @@ SELECT 101, 'Alfred', 'Döblin' FROM DUAL; 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 (i.e. if they support the SQL standard ). Here is an example how to use the ON DUPLICATE KEY UPDATE clause:

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

    The synthetic ON DUPLICATE KEY IGNORE clause

    @@ -2964,18 +2912,18 @@ create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.LAST_NAME) 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 :

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

    Postgres's INSERT .. RETURNING

    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:

    - record = create.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .values("Charlotte", "Roche") @@ -2992,7 +2940,7 @@ create.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .values("Friedrich", "Schiller") // You can request any field. Also trigger-generated values .returning(AUTHOR.ID, AUTHOR.CREATION_DATE) - .fetch();]]> + .fetch();]]>

    Some databases have poor support for returning generated keys after INSERTs. In those cases, jOOQ might need to issue another in order to fetch an @@identity value. Be aware, that this can lead to race-conditions in those databases that cannot properly return generated ID values. For more information, please consider the jOOQ Javadoc for the returning() clause. @@ -3004,50 +2952,46 @@ create.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) In some occasions, you may prefer the INSERT SELECT syntax, for instance, when you copy records from one table to another:

    -create.insertInto(AUTHOR_ARCHIVE) - .select(create.selectFrom(AUTHOR).where(AUTHOR.DECEASED.isTrue())); - -
    +create.insertInto(AUTHOR_ARCHIVE) + .select(create.selectFrom(AUTHOR).where(AUTHOR.DECEASED.isTrue()));
    The UPDATE statement - +

    The UPDATE statement is used to modify one or several pre-existing records in a database table. UPDATE statements are only possible on single tables. Support for multi-table updates will be implemented in the near future. An example update query is given here:

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

    Most databases allow for using scalar subselects in UPDATE statements in one way or another. jOOQ models this through a set(Field<T>, Select<? extends Record1<T>>) method in the UPDATE DSL API:

    - + UPDATE AUTHOR SET FIRST_NAME = ( SELECT FIRST_NAME FROM PERSON WHERE PERSON.ID = AUTHOR.ID ), - WHERE ID = 3; -create.update(AUTHOR) + WHERE ID = 3;create.update(AUTHOR) .set(AUTHOR.FIRST_NAME, select(PERSON.FIRST_NAME) .from(PERSON) .where(PERSON.ID.equal(AUTHOR.ID)) ) .where(AUTHOR.ID.equal(3)); - +

    Using row value expressions in an UPDATE statement

    @@ -3055,37 +2999,35 @@ create.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) jOOQ supports formal in various contexts, among which the UPDATE statement. Only one row value expression can be updated at a time. Here's an example:

    - + UPDATE AUTHOR SET (FIRST_NAME, LAST_NAME) = ('Hermann', 'Hesse') - WHERE ID = 3; -create.update(AUTHOR) + WHERE ID = 3;create.update(AUTHOR) .set(row(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME), row("Herman", "Hesse")) .where(AUTHOR.ID.equal(3)); - +

    This can be particularly useful when using subselects:

    - + UPDATE AUTHOR SET (FIRST_NAME, LAST_NAME) = ( SELECT PERSON.FIRST_NAME, PERSON.LAST_NAME FROM PERSON WHERE PERSON.ID = AUTHOR.ID ) - WHERE ID = 3; -create.update(AUTHOR) + WHERE ID = 3;create.update(AUTHOR) .set(row(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME), select(PERSON.FIRST_NAME, PERSON.LAST_NAME) .from(PERSON) .where(PERSON.ID.equal(AUTHOR.ID)) ) .where(AUTHOR.ID.equal(3)); - +

    The above row value expressions usages are completely typesafe. @@ -3096,45 +3038,43 @@ create.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) The Firebird and Postgres databases support a RETURNING clause on their UPDATE statements, similar as the RETURNING clause in . This is useful to fetch trigger-generated values in one go. An example is given here:

    - + - - +

    The UPDATE .. RETURNING clause is currently not simulated for other databases. Future versions might execute an additional to fetch results.

    -
    +
    The DELETE statement - +

    The DELETE statement physically removes records from a database table. DELETE statements are only possible on single tables. Support for multi-table deletes will be implemented in the near future. An example delete query is given here:

    - + DELETE AUTHOR - WHERE ID = 100; -create.delete(AUTHOR) + WHERE ID = 100;create.delete(AUTHOR) .where(AUTHOR.ID.equal(100)); - + -
    +
    The 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)

    @@ -3142,15 +3082,14 @@ RETURNING UPDATE_COUNT]]> 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 {jooq-version}, 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 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(AUTHOR) +WHEN NOT MATCHED THEN INSERT (LAST_NAME) VALUES ('Hitchcock')create.mergeInto(AUTHOR) .using(create().selectOne()) .on(AUTHOR.LAST_NAME.equal("Hitchcock")) .whenMatchedThenUpdate() @@ -3158,27 +3097,26 @@ WHEN NOT MATCHED THEN INSERT (LAST_NAME) VALUES ('Hitchcock') .whenNotMatchedThenInsert(AUTHOR.LAST_NAME) .values("Hitchcock"); - +

    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 AUTHOR (FIRST_NAME, LAST_NAME) KEY (LAST_NAME) -VALUES ('John', 'Hitchcock') -create.mergeInto(AUTHOR, +VALUES ('John', 'Hitchcock')create.mergeInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .key(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:
    @@ -3189,12 +3127,12 @@ VALUES ('John', 'Hitchcock')

    Much like the , the MERGE statement's VALUES() clause provides typesafety for degrees up to {max-row-degree}, in both the standard syntax variant as well as the H2 variant.

    -
    +
    The TRUNCATE statement - +

    The TRUNCATE statement is the only DDL statement supported by jOOQ so far. It is popular in many databases when you want to bypass constraints for table truncation. Databases may behave differently, when a truncated table is referenced by other tables. For instance, they may fail if records from a truncated table are referenced, even with ON DELETE CASCADE clauses in place. Please, consider your database manual to learn more about its TRUNCATE implementation.

    @@ -3202,44 +3140,42 @@ VALUES ('John', 'Hitchcock') The TRUNCATE syntax is trivial:

    - - TRUNCATE TABLE AUTHOR; - create.truncate(AUTHOR).execute(); - + + TRUNCATE TABLE AUTHOR;create.truncate(AUTHOR).execute(); +

    TRUNCATE is not supported by Ingres and SQLite. jOOQ will execute a DELETE FROM AUTHOR statement instead.

    -
    +
    Table expressions - +

    The following sections explain the various types of table expressions supported by jOOQ

    -
    +
    Generated Tables - +

    Most of the times, when thinking about a you're probably thinking about an actual physical table in your database schema. If you're using jOOQ's , you will have all tables from your database schema available to you as type safe Java objects. You can then use these tables in SQL , or in other , just like any other table expression. An example is given here:

    - + - + .on(AUTHOR.ID.equal(BOOK.AUTHOR_ID));]]>

    The above example shows how AUTHOR and BOOK tables are joined in a . It also shows how you can access physical by dereferencing the relevant Java attributes of their tables. @@ -3247,17 +3183,17 @@ ON (AUTHOR.ID = BOOK.AUTHOR_ID)]]>

    See the manual's section about for more information about what is really generated by the

    -
    +
    Aliased Tables - +

    The strength of jOOQ's becomes more obvious when you perform table aliasing and dereference fields from generated aliased tables. This can best be shown by example:

    - 1920 AND a.first_name = 'Paulo' - ORDER BY b.title]]> - + .orderBy(b.TITLE);]]>

    As you can see in the above example, calling as() on generated tables returns an object of the same type as the table. This means that the resulting object can be used to dereference fields from the aliased table. This is quite powerful in terms of having your Java compiler check the syntax of your SQL statements. If you remove a column from a table, dereferencing that column from that table alias will cause compilation errors. @@ -3289,40 +3224,40 @@ create.select() Only few table expressions provide the SQL syntax typesafety as shown above, where generated tables are used. Most tables, however, expose their fields through field() methods:

    - a = AUTHOR.as("a"); // Get fields from a: Field id = a.field("ID"); -Field firstName = a.field("FIRST_NAME");]]> +Field firstName = a.field("FIRST_NAME");]]>

    Derived column lists

    The SQL standard specifies how a table can be renamed / aliased in one go along with its columns. It references the term "derived column list" for the following syntax (as supported by Postgres, for instance):

    - +) t(a, b)]]>

    This feature is useful in various use-cases where column names are not known in advance (but the table's degree is!). An example for this are , or the :

    - +FROM VALUES(1, 2),(3, 4) t(a, b)]]>

    Only few databases really support such a syntax, but fortunately, jOOQ can simulate it easily using UNION ALL and an empty dummy record specifying the new column names. The two statements are equivalent:

    - +) t]]>

    In jOOQ, you would simply specify a varargs list of column aliases as such:

    - -
    +).as("t", "a", "b"));]]>
    Joined tables - +

    The that can be used in are the most powerful and best supported means of creating new in SQL. Informally, the following can be said:

    -A(colA1, ..., colAn) "join" B(colB1, ..., colBm) "produces" C(colA1, ..., colAn, colB1, ..., colBm) +A(colA1, ..., colAn) "join" B(colB1, ..., colBm) "produces" C(colA1, ..., colAn, colB1, ..., colBm)

    SQL and relational algebra distinguish between at least the following JOIN types (upper-case: SQL, lower-case: relational algebra): @@ -3375,7 +3309,7 @@ create.select().from(values( jOOQ supports all of these JOIN types (except semi-join and anti-join) directly on any :

    - table) // Various overloaded INNER JOINs @@ -3398,29 +3332,28 @@ Table crossJoin(TableLike) // Various overloaded NATURAL JOINs Table naturalJoin(TableLike) Table naturalLeftOuterJoin(TableLike) -Table naturalRightOuterJoin(TableLike)]]> +Table naturalRightOuterJoin(TableLike)]]>

    Note that most of jOOQ's JOIN operations give way to a similar DSL API hierarchy as previously seen in the manual's section about the

    -
    +
    The VALUES() table constructor - +

    Some databases allow for expressing in-memory temporary tables using a VALUES() constructor. This constructor usually works the same way as the VALUES() clause known from the or from the . With jOOQ, you can also use the VALUES() table constructor, to create tables that can be used in a :

    - + - - +

    Note, that it is usually quite useful to provide column aliases ("derived column lists") along with the table alias for the VALUES() constructor. @@ -3430,7 +3363,7 @@ FROM VALUES(1, 'a'), The above statement is simulated by jOOQ for those databases that do not support the VALUES() constructor, natively (actual simulations may vary):

    - -
    +]]>
    Nested SELECTs - +

    A can appear almost anywhere a can. Such a "nested SELECT" is often called a "derived table". Apart from many convenience methods accepting objects directly, a SELECT statement can always be transformed into a object using the asTable() method.

    Example: Scalar subquery

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

    Example: Derived table

    - + - nested = +]]> nested = create.select(BOOK.AUTHOR_ID, count().as("books")) .from(BOOK) .groupBy(BOOK.AUTHOR_ID).asTable("nested"); @@ -3497,10 +3427,10 @@ ORDER BY nested.books DESC create.select(nested.getFields()) .from(nested) .orderBy(nested.getField("books"));]]> - +

    Example: Correlated subquery

    - + - +]]> Field books = create.selectCount() .from(BOOK) @@ -3520,52 +3449,52 @@ Field books = create.select(AUTHOR.ID, books) .from(AUTHOR) .orderBy(books, AUTHOR.ID));]]> - - + +
    The Oracle 11g PIVOT clause - +

    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 .. +-- SELECT .. FROM table PIVOT (aggregateFunction [, aggregateFunction] FOR column IN (expression [, expression])) --- WHERE .. +-- WHERE ..

    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 slightly different PIVOT clause will be added later. Also, jOOQ may simulate PIVOT for other dialects in the future.

    -
    +
    jOOQ's relational division syntax - +

    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 +Assume the following cross join / cartesian product C = A × B Then it can be said that A = C ÷ B -B = C ÷ A +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) +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" +SELECT DISTINCT C.TEXT FROM C "c1" WHERE NOT EXISTS ( SELECT 1 FROM B WHERE NOT EXISTS ( @@ -3573,7 +3502,7 @@ WHERE NOT EXISTS ( 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. @@ -3587,13 +3516,13 @@ WHERE NOT EXISTS (

  • http://en.wikipedia.org/wiki/Relational_algebra#Division
  • http://www.simple-talk.com/sql/t-sql-programming/divided-we-stand-the-sql-of-relational-division/
  • -
    +
    Array and cursor unnesting - +

    The SQL standard specifies how SQL databases should implement ARRAY and TABLE types, as well as CURSOR types. Put simply, a CURSOR is a pointer to any materialised . Depending on the cursor's features, this table expression can be scrolled through in both directions, records can be locked, updated, removed, inserted, etc. Often, CURSOR types contain s, whereas ARRAY and TABLE types contain simple scalar values, although that is not a requirement

    @@ -3607,21 +3536,20 @@ WHERE NOT EXISTS ( The real power of these types become more obvious when you fetch them from to unnest them as and use them in your . An example is given here, where Oracle's DBMS_XPLAN package is used to fetch a cursor containing data about the most recent execution plan:

    - + - - +

    Note, in order to access the DbmsXplan package, you can use the to generate Oracle's SYS schema.

    -
    +
    The DUAL table - +

    The SQL standard specifies that the is optional in a . However, according to the standard, you may then no longer use some other clauses, such as the . In the real world, there exist three types of databases:

    @@ -3634,7 +3562,7 @@ FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(null, null, 'ALLSTATS'));]]> With jOOQ, you don't have to worry about the above distinction of SQL dialects. jOOQ never requires a FROM clause, but renders the necessary "DUAL" table, if needed. The following program shows how jOOQ renders "DUAL" tables

    - + - - +

    Note, that some databases (H2, MySQL) can normally do without "DUAL". However, there exist some corner-cases with complex nested SELECT statements, where this will cause syntax errors (or parser bugs). To stay on the safe side, jOOQ will always render "dual" in those dialects.

    -
    +
    Column expressions - +

    Column expressions can be used in various SQL clauses in order to refer to one or several columns. This chapter explains how to form various types of column expressions with jOOQ. A particular type of column expression is given in the section about , where an expression may have a degree of more than one.

    @@ -3686,7 +3613,7 @@ DSL.using(SQLDialect.SYBASE ).selectOne().getSQL();]]> jOOQ allows you to freely create arbitrary column expressions using a fluent expression construction API. Many expressions can be formed as functions from , other expressions can be formed based on a pre-existing column expression. For example:

    - field1 = BOOK.TITLE; // A function created from the DSL using "prefix" notation @@ -3698,31 +3625,30 @@ Field field3 = BOOK.TITLE.trim(); // More complex function with advanced DSL syntax Field field4 = listAgg(BOOK.TITLE) .withinGroupOrderBy(BOOK.ID.asc()) - .over().partitionBy(AUTHOR.ID);]]> + .over().partitionBy(AUTHOR.ID);]]>

    In general, it is up to you whether you want to use the "prefix" notation or the "postfix" notation to create new column expressions based on existing ones. The "SQL way" would be to use the "prefix notation", with functions created from the . The "Java way" or "object-oriented way" would be to use the "postfix" notation with functions created from objects. Both ways ultimately create the same query part, though.

    -
    +
    Table columns - +

    Table columns are the most simple implementations of a . They are mainly produced by jOOQ's and can be dereferenced from the generated tables. This manual is full of examples involving table columns. Another example is given in this query:

    - + - - +

    Table columns implement a more specific interface called , which is parameterised with its associated <R extends Record> record type. @@ -3730,45 +3656,43 @@ ORDER BY BOOK.TITLE]]>

    See the manual's section about for more information about what is really generated by the

    -
    +
    Aliased columns - +

    Just like , columns can be renamed using aliases. Here is an example:

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

    Here is how it's done with jOOQ:

    -Record record = create.select( +Record record = create.select( concat(AUTHOR.FIRST_NAME, val(" "), AUTHOR.LAST_NAME).as("author"), count().as("books")) .from(AUTHOR) .join(BOOK).on(AUTHOR.ID.equal(BOOK.AUTHOR_ID)) - .groupBy(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME).fetchAny(); + .groupBy(AUTHOR.FIRST_NAME, 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")); - -
    +System.out.println("Author : " + record.getValue("author")); +System.out.println("Books : " + record.getValue("books"));
    Cast expressions - +

    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 , but can also be any of , , , , , , .

    @@ -3776,27 +3700,27 @@ System.out.println("Books : " + record.getValue("books")); Sometimes, this automatic mapping might not be what you needed, or jOOQ cannot know the type of a field. In those cases you would write SQL type CAST like this:

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

    in jOOQ, you can write something like that:

    -create.select(TAuthor.LAST_NAME.cast(PostgresDataType.TEXT)); +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)); +create.select(TAuthor.LAST_NAME.cast(String.class));

    The complete CAST API in consists of these three methods:

    - { + { // Cast this field to the type of another field Field cast(Field field); @@ -3816,41 +3740,39 @@ public class DSL { Field castNull(Field field); Field castNull(DataType type); Field castNull(Class type); -}]]> -
    +}]]>
    Arithmetic expressions - +

    Numeric arithmetic expressions

    Your database can do the math for you. 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 +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); +create.select(val(1).add(2).mul(val(5).sub(3)).div(2).mod(10);

    Datetime arithmetic expressions

    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)); - + + SELECT SYSDATE + 3 FROM DUAL;create.select(currentTimestamp().add(3)); +

    For more advanced datetime arithmetic, use the DSL's timestampDiff() and dateDiff() functions, as well as jOOQ's built-in SQL standard INTERVAL data type support: @@ -3859,31 +3781,30 @@ public class DSL {

  • INTERVAL YEAR TO MONTH:
  • INTERVAL DAY TO SECOND:
  • -
    +
    String concatenation - +

    The SQL standard defines the concatenation operator to be an infix operator, similar to the ones we've seen in the chapter about . This operator looks like this: ||. Some other dialects do not support this operator, but expect a concat() function, instead. jOOQ renders the right operator / function, depending on your :

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

    There are a variety of general functions supported by jOOQ As discussed in the chapter about functions are mostly simulated in your database, in case they are not natively supported.

    @@ -3900,12 +3821,12 @@ create.select(concat("A", "B", "C"));

    Please refer to the for more details.

    -
    +
    Numeric functions - +

    Math can be done efficiently in the database before returning results to your Java application. In addition to the discussed previously, jOOQ also supports a variety of numeric functions. As discussed in the chapter about numeric functions (as any function type) are mostly simulated in your database, in case they are not natively supported.

    @@ -3947,12 +3868,12 @@ create.select(concat("A", "B", "C"));

    Please refer to the for more details.

    -
    +
    Bitwise functions - +

    Interestingly, bitwise functions and bitwise arithmetic is not very popular among SQL databases. Most databases only support a few bitwise operations, while others ship with the full set of operators. jOOQ's API includes most bitwise operations as listed below. In order to avoid ambiguities with , all bitwise functions are prefixed with "bit"

    @@ -3975,12 +3896,12 @@ create.select(concat("A", "B", "C")); http://blog.jooq.org/2011/10/30/the-comprehensive-sql-bitwise-operations-compatibility-list/

    -
    +
    String functions - +

    String formatting can be done efficiently in the database before returning results to your Java application. As discussed in the chapter about string functions (as any function type) are mostly simulated in your database, in case they are not natively supported.

    @@ -4018,18 +3939,18 @@ create.select(concat("A", "B", "C")); Various databases have some means of searching through columns using regular expressions if the does not provide sufficient pattern matching power. While there are many different functions and operators in the various databases, jOOQ settled for the SQL:2008 standard REGEX_LIKE operator. Being an operator (and not a function), you should use the corresponding method on :

    - +

    Note that the SQL standard specifies that patterns should follow the XQuery standards. In the real world, the POSIX regular expression standard is the most used one, some use Java regular expressions, and only a few ones use Perl regular expressions. jOOQ does not make any assumptions about regular expression syntax. For cross-database compatibility, please read the relevant database manuals carefully, to learn about the appropriate syntax. Please refer to the for more details.

    -
    +
    Date and time functions - +

    This is a list of date and time functions supported by jOOQ's :

    @@ -4048,29 +3969,29 @@ create.select(concat("A", "B", "C"));

    jOOQ fills a gap opened by JDBC, which neglects an important SQL data type as defined by the SQL standards: INTERVAL types. See the manual's section about for more details.

    -
    +
    System functions - +

    This is a list of system functions supported by jOOQ's :

    • CURRENT_USER: Get current user.
    -
    +
    Aggregate functions - +

    Aggregate functions work just like functions, even if they have a slightly different semantics. Here are some example aggregate functions from the :

    - count(); AggregateFunction count(Field field); AggregateFunction max (Field field); @@ -4107,20 +4028,19 @@ AggregateFunction regrR2 (Field y, Field regrSlope (Field y, Field x); AggregateFunction regrSXX (Field y, Field x); AggregateFunction regrSXY (Field y, Field x); -AggregateFunction regrSYY (Field y, Field x);]]> +AggregateFunction regrSYY (Field y, Field x);]]>

    Here's an example, counting the number of books any author has written:

    - + SELECT AUTHOR_ID, COUNT(*) FROM BOOK -GROUP BY AUTHOR_ID -create.select(BOOK.AUTHOR_ID, count()) +GROUP BY AUTHOR_IDcreate.select(BOOK.AUTHOR_ID, count()) .from(BOOK) .groupBy(BOOK.AUTHOR_ID); - +

    Aggregate functions have strong limitations about when they may be used and when not. For instance, you can use aggregate functions in scalar queries. Typically, this means you only select aggregate functions, no or other . Another use case is to use them along with a as seen in the previous example. Note, that jOOQ does not check whether your using of aggregate functions is correct according to the SQL standards, or according to your database's behaviour. @@ -4130,39 +4050,37 @@ GROUP BY AUTHOR_ID

    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 Oracle's LISTAGG() (also known as GROUP_CONCAT in other ). 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, ", ") +GROUP BY AUTHOR_IDcreate.select(listAgg(BOOK.TITLE, ", ") .withinGroupOrderBy(BOOK.TITLE)) .from(BOOK) .groupBy(BOOK.AUTHOR_ID) - +

    The above query might yield:

    -+---------------------+ ++---------------------+ | LISTAGG | +---------------------+ | 1984, Animal Farm | | O Alquimista, Brida | -+---------------------+ ++---------------------+

    FIRST and LAST: Oracle's "ranked" aggregate functions

    Oracle allows for restricting aggregate functions using the KEEP() clause, which is supported by jOOQ. In Oracle, some aggregate functions (MIN, MAX, SUM, AVG, COUNT, VARIANCE, or STDDEV) can be restricted by this clause, hence also allows for specifying it. Here are a couple of examples using this clause:

    - + SUM(BOOK.AMOUNT_SOLD) - KEEP(DENSE_RANK FIRST ORDER BY BOOK.AUTHOR_ID) -sum(BOOK.AMOUNT_SOLD) + KEEP(DENSE_RANK FIRST ORDER BY BOOK.AUTHOR_ID)sum(BOOK.AMOUNT_SOLD) .keepDenseRankFirstOrderBy(BOOK.AUTHOR_ID) - +

    User-defined aggregate functions

    @@ -4173,12 +4091,12 @@ GROUP BY AUTHOR_ID

    In those databases that support , jOOQ's can be transformed into a window function / analytical function by calling over() on it. See the manual's section about for more details.

    -
    +
    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. Note, that H2 and HSQLDB have implemented ROW_NUMBER() functions, without true windowing support.

    @@ -4186,7 +4104,7 @@ GROUP BY AUTHOR_ID As previously discussed, any can be transformed into a window function using the over() method. See the chapter about for details. In addition to those, there are also some more window functions supported by jOOQ, as declared in the :

    - rowNumber(); WindowOverStep rank(); WindowOverStep denseRank(); @@ -4206,7 +4124,7 @@ GROUP BY AUTHOR_ID // Statistical functions WindowOverStep cumeDist(); - WindowOverStep ntile(int number);]]> + WindowOverStep ntile(int number);]]>

    SQL distinguishes between various window function types (e.g. "ranking functions"). Depending on the function, SQL expects mandatory PARTITION BY or ORDER BY clauses within the OVER() clause. jOOQ does not enforce those rules for two reasons: @@ -4223,7 +4141,7 @@ GROUP BY AUTHOR_ID Here are some simple examples of window functions with jOOQ:

    - + -- Sample uses of ROW_NUMBER() ROW_NUMBER() OVER() ROW_NUMBER() OVER(PARTITION BY 1) @@ -4234,8 +4152,7 @@ ROW_NUMBER() OVER(PARTITION BY BOOK.AUTHOR_ID ORDER BY BOOK.ID) FIRST_VALUE(BOOK.ID) OVER() FIRST_VALUE(BOOK.ID IGNORE NULLS) OVER() FIRST_VALUE(BOOK.ID RESPECT NULLS) OVER() - -// Sample uses of rowNumber() +// Sample uses of rowNumber() rowNumber().over() rowNumber().over().partitionByOne() rowNumber().over().partitionBy(BOOK.AUTHOR_ID) @@ -4246,27 +4163,26 @@ firstValue(BOOK.ID).over() firstValue(BOOK.ID).ignoreNulls().over() firstValue(BOOK.ID).respectNulls().over() - +

    An advanced window function example

    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). Window functions are accessible from the previously seen 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, + FROM transactionscreate.select(t.BOOKED_AT, t.AMOUNT, sum(t.AMOUNT).over().partitionByOne() .orderBy(t.BOOKED_AT) .rowsBetweenUnboundedPreceding() .andCurrentRow().as("total") .from(TRANSACTIONS.as("t")); - +

    Window functions created from ordered aggregate functions

    @@ -4274,48 +4190,46 @@ firstValue(BOOK.ID).respectNulls().over() In the previous chapter about , we have seen the concept of "ordered aggregate functions", such as Oracle's LISTAGG(). These functions have a window function / analytical function variant, as well. For example:

    - + SELECT LISTAGG(TITLE, ', ') WITHIN GROUP (ORDER BY TITLE) OVER (PARTITION BY BOOK.AUTHOR_ID) -FROM BOOK -create.select(listAgg(BOOK.TITLE, ", ") +FROM BOOKcreate.select(listAgg(BOOK.TITLE, ", ") .withinGroupOrderBy(BOOK.TITLE) .over().partitionBy(BOOK.AUTHOR_ID)) .from(BOOK) - +

    Window functions created from Oracle's FIRST and LAST aggregate functions

    In the previous chapter about , we have seen the concept of "FIRST and LAST aggregate functions". These functions have a window function / analytical function variant, as well. For example:

    - + SUM(BOOK.AMOUNT_SOLD) KEEP(DENSE_RANK FIRST ORDER BY BOOK.AUTHOR_ID) - OVER(PARTITION BY 1) -sum(BOOK.AMOUNT_SOLD) + OVER(PARTITION BY 1)sum(BOOK.AMOUNT_SOLD) .keepDenseRankFirstOrderBy(BOOK.AUTHOR_ID) .over().partitionByOne() - +

    Window functions created from user-defined aggregate functions

    User-defined aggregate functions also implement , hence they can also be transformed into window functions using over(). This is supported by Oracle in particular. See the manual's section about for more details.

    -
    +
    Grouping functions - +

    ROLLUP() explained in SQL

    The SQL standard defines special functions that can be used in the : the grouping functions. These functions can be used to generate several groupings in a single clause. This can best be explained in SQL. Let's take ROLLUP() for instance:

    - + - - +

    In English, the ROLLUP() grouping function provides N+1 groupings, when N is the number of arguments to the ROLLUP() function. Each grouping has an additional group field from the ROLLUP() argument field list. The results of the second query might look something like this:

    - ++-----------+--------------+----------+]]>

    CUBE() explained in SQL

    CUBE() is different from ROLLUP() in the way that it doesn't just create N+1 groupings, it creates all 2^N possible combinations between all group fields in the CUBE() function argument list. Let's re-consider our second query from before:

    - + - - +

    The results would then hold:

    - ++-----------+--------------+----------+]]>

    GROUPING SETS()

    @@ -4444,7 +4356,7 @@ ORDER BY 1 NULLS FIRST, 2 NULLS FIRST jOOQ fully supports all of these functions, as well as the utility functions GROUPING() and GROUPING_ID(), used for identifying the grouping set ID of a record. The thus includes:

    -... fields); GroupField cube(Field... fields); GroupField groupingSets(Field... fields); @@ -4453,66 +4365,64 @@ GroupField groupingSets(Collection>... fields); // The utility functions generating IDs per GROUPING SET Field grouping(Field); -Field groupingId(Field...);]]> +Field groupingId(Field...);]]>

    MySQL's and CUBRID's WITH ROLLUP syntax

    MySQL and CUBRID don't know any grouping functions, but they support a WITH ROLLUP clause, that is equivalent to simple ROLLUP() grouping functions. jOOQ simulates ROLLUP() in MySQL and CUBRID, by rendering this WITH ROLLUP clause. The following two statements mean the same:

    - + - - -
    + +
    User-defined functions - +

    Some databases support user-defined functions, which can be embedded in any SQL statement, if you're using jOOQ's . Let's say you have the following simple function in Oracle SQL:

    - +]]>

    The above function will be made available from a generated class. You can use it like any other :

    - - - - + + +

    Note that user-defined functions returning or data types can also be used wherever can be used, if they are

    -
    +
    User-defined aggregate functions - +

    Some databases support user-defined aggregate functions, which can then be used along with or as . An example for such a database is Oracle. With Oracle, you can define the following OBJECT type (the example was taken from the Oracle 11g documentation):

    - +END;]]>

    The above OBJECT type is then available to function declarations as such:

    - +PARALLEL_ENABLE AGGREGATE USING U_SECOND_MAX;]]>

    Using the generated aggregate function

    jOOQ's will detect such aggregate functions and generate them differently from regular . They implement the type, as mentioned in the manual's section about . Here's how you can use the SECOND_MAX() aggregate function with jOOQ:

    - + - - -
    + +
    The CASE expression - +

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

    - + - - +

    In jOOQ, both syntaxes are supported (The second one is simulated in Derby, which only knows the first one). 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. @@ -4629,15 +4537,15 @@ create.decode().value(AUTHOR.FIRST_NAME) A CASE expression can be used anywhere where you can place a . For instance, you can SELECT the above expression, if you're selecting from AUTHOR:

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

    The Oracle DECODE() function

    Oracle knows a more succinct, but maybe less readable DECODE() function with a variable number of arguments. This function roughly does the same as the second case expression syntax. jOOQ supports the DECODE() function and simulates it using CASE expressions in all dialects other than Oracle:

    - + - - +

    CASE clauses in an ORDER BY clause

    Sort indirection is often implemented with a CASE clause of a SELECT's ORDER BY clause. See the manual's section about the for more details.

    -
    +
    Sequences and serials - +

    Sequences implement the interface, providing essentially this functionality:

    - currval(); // Get a field for the NEXTVAL sequence property -Field nextval();]]> +Field nextval();]]>

    So if you have a sequence like this in Oracle:

    -CREATE SEQUENCE s_author_id +CREATE SEQUENCE s_author_id

    You can then use your object directly in a SQL statement as such:

    - +]]>
    • For more information about generated sequences, refer to the manual's section about
    • For more information about executing standalone calls to sequences, refer to the manual's section about
    -
    +
    Tuples or row value expressions - +

    According to the SQL standard, row value expressions can have a degree of more than one. This is commonly used in the , where the VALUES row value constructor allows for providing a row value expression as a source for INSERT data. Row value expressions can appear in various other places, though. They are supported by jOOQ as records / rows. jOOQ's allows for the construction of type-safe records up to the degree of {max-row-degree}. Higher-degree Rows are supported as well, but without any type-safety. Row types are modelled as follows:

    - Row1 row(T1 t1) { ... } public static Row2 row(T1 t1, T2 t2) { ... } public static Row3 row(T1 t1, T2 t2, T3 t3) { ... } @@ -4722,7 +4629,7 @@ public static Row4 row(T1 t1, T2 t2, T3 t3, T4 // [ ... idem for Row5, Row6, Row7, ..., Row{max-row-degree} ] // Degrees of more than {max-row-degree} are supported without type-safety -public static RowN row(Object... values) { ... }]]> +public static RowN row(Object... values) { ... }]]>

    Using row value expressions in predicates

    @@ -4748,14 +4655,14 @@ public static RowN row(Object... values) { ... }]]>

    jOOQ chose to explicitly support degrees up to {max-row-degree} to match Scala's typesafe tuple, function and product support. Unlike Scala, however, jOOQ also supports higher degrees without the additional typesafety.

    -
    +
    Conditional expressions - +

    Conditions or conditional expressions are widely used in SQL and in the jOOQ API. They can be used in

    @@ -4792,22 +4699,21 @@ public static RowN row(Object... values) { ... }]]>

    Note that jOOQ does not model these values as actual compatible.

    -
    +
    Condition building - +

    With jOOQ, most are built from , calling various methods on them. For instance, to build a , you can write the following expression:

    - + - - +

    Create conditions from the DSL

    @@ -4823,48 +4729,47 @@ BOOK.TITLE.notEqual("Animal Farm")]]>

    Conditions can also be connected using as will be discussed in a subsequent chapter.

    -
    +
    AND, OR, NOT boolean operators - +

    In SQL, as in most other languages, can be connected using the AND and OR binary operators, as well as the NOT unary operator, to form new conditional expressions. In jOOQ, this is modelled as such:

    - + - - +

    The above example shows that the number of parentheses in Java can quickly explode. Proper indentation may become crucial in making such code readable. In order to understand how jOOQ composes combined conditional expressions, let's assign component expressions first:

    - +Condition combined2 = combined1.andNot(c); // The left-hand side of the AND NOT () operator is already wrapped in parentheses]]>

    The Condition API

    Here are all boolean operators on the interface:

    -) // Combine conditions with OR. Convenience for adding orNot(Condition) // Combine conditions with OR. Convenience for adding an inverted condition to the rhs orNotExists(Select) // Combine conditions with OR. Convenience for adding an inverted exists predicate to the rhs -not() // Invert a condition (synonym for DSL.not(Condition)]]> -
    +not() // Invert a condition (synonym for DSL.not(Condition)]]>
    Comparison predicate - +

    In SQL, comparison predicates are formed using common comparison operators:

    @@ -4903,7 +4807,7 @@ not() // Invert a condition (synonym for DSL.not(Condition)] Unfortunately, Java does not support operator overloading, hence these operators are also implemented as methods in jOOQ, like any other SQL syntax elements. The relevant parts of the interface are these:

    -); // = (some column expression) eq or equal(Select>); // = (some scalar SELECT statement) ne or notEqual(T); // <> (some bind value) @@ -4920,7 +4824,7 @@ gt or greaterThan(Field); // > (some column expressio gt or greaterThan(Select>); // > (some scalar SELECT statement) ge or greaterOrEqual(T); // >= (some bind value) ge or greaterOrEqual(Field); // >= (some column expression) -ge or greaterOrEqual(Select>); // >= (some scalar SELECT statement)]]> +ge or greaterOrEqual(Select>); // >= (some scalar SELECT statement)]]>

    Note that every operator is represented by two methods. A verbose one (such as equal()) and a two-character one (such as eq()). Both methods are the same. You may choose either one, depending on your taste. The manual will always use the more verbose one. @@ -4931,25 +4835,24 @@ ge or greaterOrEqual(Select>); // >= (some scalar SELECT st In addition to the above, jOOQ provides a few convenience methods for common operations performed on strings using comparison predicates:

    - + LOWER('animal farm')]]> - LOWER('animal farm')]]> - -
    + +
    Comparison predicate (degree > 1) - +

    All variants of the that we've seen in the previous chapter also work for . If your database does not support row value expression comparison predicates, jOOQ simulates them the way they are defined in the SQL standard:

    - + (A, B) <> (X, Y) (A, B) < (X, Y) -(A, B) <= (X, Y)]]> - NOT((A, B) = (X, Y)) NOT((A, B) >= (X, Y)) NOT((A, B) > (X, Y))]]> - +

    jOOQ supports all of the above row value expression comparison predicates, both with and at the right-hand side:

    - + (X, Y))]]> SELECT PERSON.ID, 'Animal Farm' FROM PERSON WHERE PERSON.ID = 1 -)]]> - - -
    + +
    Quantified comparison predicate - +

    If the right-hand side of a turns out to be a non-scalar table subquery, you can wrap that subquery in a quantifier, such as ALL, ANY, or SOME. Note that the SQL standard defines ANY and SOME to be equivalent. jOOQ settled for the more intuitive ANY and doesn't support SOME. Here are some examples, supported by jOOQ:

    - + ALL(1920, 1940)]]> - ALL(1920, 1940)]]> - +

    For the example, the right-hand side of the quantified comparison predicates were filled with argument lists. But it is easy to imagine that the source of values results from a . @@ -5046,63 +4946,60 @@ BOOK.PUBLISHED_IN.greaterThan(all(1920, 1940));]]> It is interesting to note that the SQL standard defines the in terms of the ANY-quantified predicate. The following two expressions are equivalent:

    - - - - + + +

    Typically, the is more readable than the quantified comparison predicate.

    -
    +
    NULL predicate - +

    In SQL, you cannot compare NULL with any value using , as the result would yield NULL again, which is neither TRUE nor FALSE (see also the manual's section about ). In order to test a for NULL, use the NULL predicate as such:

    - + - - + -
    +
    NULL predicate (degree > 1) - +

    The SQL NULL predicate also works well for , although it has some subtle, counter-intuitive features when it comes to inversing predicates with the NOT() operator! Here are some examples:

    - + - - +

    The SQL standard contains a nice truth table for the above rules:

    -+-----------------------+-----------+---------------+---------------+-------------------+ ++-----------------------+-----------+---------------+---------------+-------------------+ | Expression | R IS NULL | R IS NOT NULL | NOT R IS NULL | NOT R IS NOT NULL | +-----------------------+-----------+---------------+---------------+-------------------+ | degree 1: null | true | false | false | true | @@ -5110,21 +5007,19 @@ NOT((A, B) IS NOT NULL)]]> | degree > 1: all null | true | false | false | true | | degree > 1: some null | false | false | true | true | | degree > 1: none null | false | true | true | false | -+-----------------------+-----------+---------------+---------------+-------------------+ ++-----------------------+-----------+---------------+---------------+-------------------+

    In jOOQ, you would simply use the isNull() and isNotNull() methods on row value expressions. Again, as with the , the row value expression NULL predicate is simulated by jOOQ, if your database does not natively support it:

    - - -
    +
    DISTINCT predicate - +

    Some databases support the DISTINCT predicate, which serves as a convenient, NULL-safe . With the DISTINCT predicate, the following truth table can be assumed:

    @@ -5138,18 +5033,17 @@ row(BOOK.ID, BOOK.TITLE).isNotNull();]]> For instance, you can compare two fields for distinctness, ignoring the fact that any of the two could be NULL, which would lead to funny results. This is supported by jOOQ as such:

    - + - - +

    If your database does not natively support the DISTINCT predicate, jOOQ simulates it with an equivalent , modelling the above truth table:

    - + - - -
    + +
    BETWEEN predicate - +

    The BETWEEN predicate can be seen as syntactic sugar for a pair of . According to the SQL standard, the following two predicates are equivalent:

    - - -= [B] AND [A] <= [C]]]> - + += [B] AND [A] <= [C]]]> +

    Note the inclusiveness of range boundaries in the definition of the BETWEEN predicate. Intuitively, this is supported in jOOQ as such:

    - + - - +

    BETWEEN SYMMETRIC

    The SQL standard defines the SYMMETRIC keyword to be used along with BETWEEN to indicate that you do not care which bound of the range is larger than the other. A database system should simply swap range bounds, in case the first bound is greater than the second one. jOOQ supports this keyword as well, simulating it if necessary.

    - + - - +

    The simulation is done trivially:

    - - - - + + + -
    +
    BETWEEN predicate (degree > 1) - +

    The SQL BETWEEN predicate also works well for . Much like the , it is defined in terms of a pair of regular :

    - + -= [B] AND [A] <= [C] +[A] BETWEEN SYMMETRIC [B] AND [C]]]>= [B] AND [A] <= [C] ([A] >= [B] AND [A] <= [C]) OR ([A] >= [C] AND [A] <= [B])]]> - +

    The above can be factored out according to the rules listed in the manual's section about . @@ -5239,14 +5127,12 @@ BOOK.PUBLISHED_IN.notBetweenSymmetric(1940).and(1920)]]> jOOQ supports the BETWEEN [SYMMETRIC] predicate and simulates it in all SQL dialects where necessary. An example is given here:

    - - -
    +
    LIKE predicate - +

    LIKE predicates are popular for simple wildcard-enabled pattern matching. Supported wildcards in all SQL databases are:

    @@ -5258,24 +5144,22 @@ BOOK.PUBLISHED_IN.notBetweenSymmetric(1940).and(1920)]]> With jOOQ, the LIKE predicate can be created from any as such:

    - + - - +

    Escaping operands with the LIKE predicate

    Often, your pattern may contain any of the wildcard characters "_" and "%", in case of which you may want to escape them. jOOQ does not automatically escape patterns in like() and notLike() methods. Instead, you can explicitly define an escape character as such:

    - + - - +

    In the above predicate expressions, the exclamation mark character is passed as the escape character to escape wildcard characters "!_" and "!%", as well as to escape the escape character itself: "!!" @@ -5289,7 +5173,7 @@ BOOK.TITLE.notLike("%The !%-Sign Book%", '!')]]> In addition to the above, jOOQ provides a few convenience methods for common operations performed on strings using the LIKE predicate. Typical operations are "contains predicates", "starts with predicates", "ends with predicates", etc. Here is the full convenience API wrapping LIKE predicates:

    - + - - +

    Note, that jOOQ escapes % and _ characters in value in some of the above predicate implementations. For simplicity, this has been omitted in this manual.

    -
    +
    IN predicate - +

    In SQL, apart from comparing a value against several values, the IN predicate can be used to create semi-joins or anti-joins. jOOQ knows the following methods on the interface, to construct such IN predicates:

    -) // Construct an IN predicate from a collection of bind values +) // Construct an IN predicate from a collection of bind values in(T...) // Construct an IN predicate from bind values in(Field...) // Construct an IN predicate from column expressions in(Select>) // Construct an IN predicate from a subselect notIn(Collection) // Construct a NOT IN predicate from a collection of bind values notIn(T...) // Construct a NOT IN predicate from bind values notIn(Field...) // Construct a NOT IN predicate from column expressions -notIn(Select>) // Construct a NOT IN predicate from a subselect]]> +notIn(Select>) // Construct a NOT IN predicate from a subselect]]>

    A sample IN predicate might look like this:

    - + - - +

    NOT IN and NULL values

    @@ -5347,7 +5229,7 @@ BOOK.TITLE.notIn("Animal Farm", "1984")]]> Beware that you should probably not have any NULL values in the right hand side of a NOT IN predicate, as the whole expression would evaluate to NULL, which is rarely desired. This can be shown informally using the following reasoning:

    --- The following conditional expressions are formally or informally equivalent +-- The following conditional expressions are formally or informally equivalent A NOT IN (B, C) A != ANY(B, C) A != B AND A != C @@ -5356,37 +5238,35 @@ A != B AND A != C A NOT IN (B, NULL) -- Substitute C for NULL A != B AND A != NULL -- From the above rules A != B AND NULL -- [ANY] != NULL yields NULL -NULL -- [ANY] AND NULL yields NULL +NULL -- [ANY] AND NULL yields NULL

    A good way to prevent this from happening is to use the for anti-joins, which is NULL-value insensitive. See the manual's section about to see a boolean truth table.

    -
    +
    IN predicate (degree > 1) - +

    The SQL IN predicate also works well for . Much like the , it is defined in terms of a . The two expressions are equivalent:

    - - - - + + +

    jOOQ supports the IN predicate. Simulation of the IN predicate where row value expressions aren't well supported is currently only available for IN predicates that do not take a subselect as an IN predicate value. An example is given here:

    - -
    +
    EXISTS predicate - +

    Slightly less intuitive, yet more powerful than the previously discussed is the EXISTS predicate, that can be used to form semi-joins or anti-joins. With jOOQ, the EXISTS predicate can be formed in various ways:

    @@ -5400,16 +5280,15 @@ NULL -- [ANY] AND NULL yields NULL An example of an EXISTS predicate can be seen here:

    - + - - +

    Note that in SQL, the projection of a subselect in an EXISTS predicate is irrelevant. To help you write queries like the above, you can use jOOQ's selectZero() or selectOne() methods @@ -5420,60 +5299,59 @@ notExists(create.selectOne().from(BOOK) In theory, the two types of predicates can perform equally well. If your database system ships with a sophisticated cost-based optimiser, it will be able to transform one predicate into the other, if you have all necessary constraints set (e.g. referential constraints, not null constraints). However, in reality, performance between the two might differ substantially. An interesting blog post investigating this topic on the MySQL database can be seen here:
    http://blog.jooq.org/2012/07/27/not-in-vs-not-exists-vs-left-join-is-null-mysql/

    -
    +
    OVERLAPS predicate - +

    When comparing dates, the SQL standard allows for using a special OVERLAPS predicate, which checks whether two date ranges overlap each other. The following can be said:

    - +(DATE '2010-01-02', CAST('+2 00:00:00' AS INTERVAL DAY TO SECOND))]]>

    The OVERLAPS predicate in jOOQ

    jOOQ supports the OVERLAPS predicate on . The following methods are contained in :

    - t1, Field t2); -Condition overlaps(Row2 row);]]> +Condition overlaps(Row2 row);]]>

    This allows for expressing the above predicates as such:

    - +row(Date.valueOf('2010-01-01'), new DayToSecond(2)).overlaps(Date.valueOf('2010-01-02'), new DayToSecond(2))]]>

    jOOQ's extensions to the standard

    Unlike the standard (or any database implementing the standard), jOOQ also supports the OVERLAPS predicate for comparing arbitrary . For instance, (1, 3) OVERLAPS (2, 4) will yield true in jOOQ. This is simulated as such

    - -
    +(C <= B) AND (A <= D)]]>
    Plain SQL - +

    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 a host language (Java in this case), which was not made for exactly the same purposes as its hosted 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 by language constraints of its host language. We have seen many functionalities where the DSL becomes a bit verbose. This can be especially true for:

    @@ -5502,7 +5380,7 @@ row(Date.valueOf('2010-01-01'), new DayToSecond(2)).overlaps(Date.valueOf('2010-

    Plain SQL API methods are usually overloaded in three ways. Let's look at the condition query part constructor:

    - +Condition condition(String sql, QueryPart... parts);]]>

    Please refer to the Javadoc for more details. The following is a more complete listing of plain SQL construction methods from the DSL:

    - resultQuery(String sql, QueryPart... parts); // A query with results. This is the same as resultQuery(...).fetch(); Result fetch(String sql); Result fetch(String sql, Object... bindings); -Result fetch(String sql, QueryPart... parts);]]> +Result fetch(String sql, QueryPart... parts);]]>

    Apart from the general factory methods, plain SQL is also available 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"); @@ -5598,7 +5476,7 @@ create.select(LAST_NAME, COUNT1, COUNT2) // Use plain SQL again as fields in GROUP BY and ORDER BY clauses .groupBy(LAST_NAME) - .orderBy(LAST_NAME);]]> + .orderBy(LAST_NAME);]]>

    Important things to note about plain SQL!

    @@ -5610,12 +5488,12 @@ create.select(LAST_NAME, COUNT1, COUNT2)

  • 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.
  • -
    +
    Bind values and parameters - +

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

    @@ -5634,31 +5512,31 @@ create.select(LAST_NAME, COUNT1, COUNT2)

    The following sections explain how you can introduce bind values in jOOQ, and how you can control the way they are rendered and bound to SQL.

    -
    +
    Indexed parameters - +

    JDBC only knows indexed bind values. A typical example for using bind values with JDBC is this:

    - +stmm.executeQuery();]]>

    With dynamic SQL, keeping track of the number of question marks and their corresponding index may turn out to be hard. jOOQ abstracts this and lets you provide the bind value right where it is needed. A trivial example is this:

    - +create.select().from(BOOK).where(BOOK.ID.equal(val(5))).and(BOOK.TITLE.equal(val("Animal Farm")));]]>

    Note the using of to explicitly create an indexed bind value. You don't have to worry about that index. When the query is , each bind value will render a question mark. When the query , each bind value will generate the appropriate bind value index. @@ -5669,7 +5547,7 @@ create.select().from(BOOK).where(BOOK.ID.equal(val(5))).and(BOOK.TITLE.equal(val Should you decide to run the above query outside of jOOQ, using your own , you can do so as follows:

    - select = create.select().from(BOOK).where(BOOK.ID.equal(5)).and(BOOK.TITLE.equal("Animal Farm")); + select = create.select().from(BOOK).where(BOOK.ID.equal(5)).and(BOOK.TITLE.equal("Animal Farm")); // Render the SQL statement: String sql = select.getSQL(); @@ -5679,34 +5557,34 @@ assertEquals("SELECT * FROM BOOK WHERE ID = ? AND TITLE = ?", sql); List values = select.getBindValues(); assertEquals(2, values.size()); assertEquals(5, values.get(0)); -assertEquals("Animal Farm", values.get(1));]]> +assertEquals("Animal Farm", values.get(1));]]>

    You can also extract specific bind values by index from a query, if you wish to modify their underlying value after creating a query. This can be achieved as such:

    - select = create.select().from(BOOK).where(BOOK.ID.equal(5)).and(BOOK.TITLE.equal("Animal Farm")); + select = create.select().from(BOOK).where(BOOK.ID.equal(5)).and(BOOK.TITLE.equal("Animal Farm")); Param param = select.getParam("2"); // You could now modify the Query's underlying bind value: if ("Animal Farm".equals(param.getValue())) { param.setConverted("1984"); -}]]> +}]]>

    For more details about jOOQ's internals, see the manual's section about .

    - +
    Named parameters - +

    Some SQL access abstractions that are built on top of JDBC, or some that bypass JDBC may support named parameters. jOOQ allows you to give names to your parameters as well, although those names are not rendered to SQL strings by default. Here is an example of how to create named parameters using the type:

    - param1 = query.getParam("lastName"); @@ -5715,41 +5593,40 @@ Param param2 = param("lastName", "Poe"); Query query2 = create.select().from(AUTHOR).where(LAST_NAME.equal(param2)); // You can now change the bind value directly on the Param reference: -param2.setValue("Orwell");]]> +param2.setValue("Orwell");]]>

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

    - +query2.bind("lastName", "Orwell");]]>

    In order to actually render named parameter names in generated SQL, use the method:

    - + - - -
    + +
    Inlined parameters - +

    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:

    @@ -5765,7 +5642,7 @@ WHERE LAST_NAME = :lastName]]> In both cases, your inlined bind values will be properly escaped to avoid SQL syntax errors and SQL injection. Some examples:

    - -
    + .where(LAST_NAME.equal("Poe"));]]>
    SQL injection and plain SQL QueryParts - +

    Special care needs to be taken when using . While jOOQ's API allows you to specify bind values for use with plain SQL, you're not forced to do that. For instance, both of the following queries will lead to the same, valid result:

    - +create.fetch("SELECT * FROM BOOK WHERE ID = 5 AND TITLE = 'Animal Farm'");]]>

    All methods in the jOOQ API that allow for plain (unescaped, untreated) SQL contain a warning message in their relevant Javadoc, to remind you of the risk of SQL injection in what is otherwise a SQL-injection-safe API.

    -
    +
    QueryParts - +

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

    @@ -5827,12 +5703,12 @@ create.fetch("SELECT * FROM BOOK WHERE ID = 5 AND TITLE = 'Animal Farm'");]]> The following sections explain some more details about and , as well as other implementation details about QueryParts in general.

    -
    +
    SQL rendering - +

    Every must implement the method to render its SQL string to a . This RenderContext has two purposes:

    @@ -5844,7 +5720,7 @@ create.fetch("SELECT * FROM BOOK WHERE ID = 5 AND TITLE = 'Animal Farm'");]]> API is given here:

    - +RenderContext castModeSome(SQLDialect... dialects);]]>

    The following additional methods are inherited from a common , which is shared among and :

    - +int peekIndex();]]>

    An example of rendering SQL

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

    --- [...] +-- [...] FROM AUTHOR JOIN BOOK ON AUTHOR.ID = BOOK.AUTHOR_ID --- [...] +-- [...]

    This is how jOOQ renders such a condition (simplified example):

    - +}]]>

    See the manual's sections about and to learn about how to write your own query parts in order to extend jOOQ.

    -
    +
    Pretty printing SQL - +

    As mentioned in the previous chapter about , there are some elements in the that are used for formatting / pretty-printing rendered SQL. In order to obtain pretty-printed SQL, just use the following :

    - +

    And then, use the above DSLContext to render pretty-printed SQL:

    - + - '1984' group by "TEST"."AUTHOR"."LAST_NAME" having count(*) = 2]]> - +

    The section about shows an example of how such pretty printing can be used to log readable SQL to the stdout.

    -
    +
    Variable binding - +

    Every must implement the method. This BindContext has two purposes:

    @@ -5987,7 +5862,7 @@ having count(*) = 2]]> An overview of the API is given here:

    - type) throws DataAccessException; -BindContext bindValues(Object... values) throws DataAccessException;]]> +BindContext bindValues(Object... values) throws DataAccessException;]]>

    Some additional methods are inherited from a common , which is shared among and . Details are documented in the previous chapter about @@ -6008,43 +5883,43 @@ BindContext bindValues(Object... values) throws DataAccessException;]]> A simple example can be provided by checking out jOOQ's internal representation of a (simplified) . It is used for any comparing two fields as for example the AUTHOR.ID = BOOK.AUTHOR_ID condition here:

    --- [...] +-- [...] WHERE AUTHOR.ID = ? --- [...] +-- [...]

    This is how jOOQ binds values on such a condition:

    - +}]]>

    See the manual's sections about and to learn about how to write your own query parts in order to extend jOOQ.

    -
    +
    Extend jOOQ with custom types - +

    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:

    - extends AbstractField {} + extends AbstractField {} public abstract class CustomCondition extends AbstractCondition {} public abstract class CustomTable> extends TableImpl {} -public abstract class CustomRecord> extends TableRecordImpl {}]]> +public abstract class CustomRecord> extends TableRecordImpl {}]]>

    These classes are declared public and covered by jOOQ's integration tests. When you extend these classes, you will have to provide your own implementations for the and methods, as discussed before:

    - +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. Here's an example showing how to create a field multiplying another field by 2

    - IDx2 = new CustomField(BOOK.ID.getName(), BOOK.ID.getDataType()) { @Override public void toSQL(RenderContext context) { @@ -6094,13 +5969,12 @@ final Field IDx2 = new CustomField(BOOK.ID.getName(), BOOK.ID. }; // Use the above field in a SQL statement: -create.select(IDx2).from(BOOK);]]> -
    +create.select(IDx2).from(BOOK);]]>
    Plain SQL QueryParts - +

    If you don't need the 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. Plain SQL methods in jOOQ's API come in two flavours.

    @@ -6112,29 +5986,29 @@ create.select(IDx2).from(BOOK);]]> The above distinction is best explained using an example:

    - id = val(5); Field title = val("Animal Farm"); -create.selectFrom(BOOK).where("BOOK.ID = {0} AND TITLE = {1}", id, title);]]> +create.selectFrom(BOOK).where("BOOK.ID = {0} AND TITLE = {1}", id, title);]]>

    The above technique allows for creating rather complex SQL clauses that are currently not supported by jOOQ, without extending any of the as indicated in the previous chapter.

    -
    +
    Serializability - +

    The only transient, non-serializable element in any jOOQ object is the underlying . When you want to execute queries after de-serialisation, or when you want to store/refresh/delete , you may have to "re-attach" them to a Configuration

    - select = (Select) in.readObject(); @@ -6143,20 +6017,20 @@ select.execute(); // In order to execute the above select, attach it first DSLContext create = DSL.using(connection, SQLDialect.ORACLE); -create.attach(select);]]> +create.attach(select);]]>

    Automatically attaching QueryParts

    Another way of attaching QueryParts automatically, or rather providing them with a new at will, is to hook into the . More details about this can be found in the manual's chapter about

    -
    +
    SQL building in Scala - +

    jOOQ-Scala is a maven module used for leveraging some advanced Scala features for those users that wish to use jOOQ with Scala.

    @@ -6169,7 +6043,7 @@ create.attach(select);]]> The following depicts a trait which wraps all fields:

    -(value : T) : Condition def <=>(value : Field[T]) : Condition -}]]> +}]]>

    The following depicts a trait which wraps numeric fields:

    ->(value : T) : Field[T] def >>(value : Field[T]) : Field[T] -}]]> +}]]>

    An example query using such overloaded operators would then look like this:

    - 2) or (T_BOOK.TITLE in ("O Alquimista", "Brida")) -fetch]]> +fetch]]>

    Scala 2.10 Macros

    This feature is still being experimented with. With Scala Macros, it might be possible to inline a true SQL dialect into the Scala syntax, backed by the jOOQ API. Stay tuned!

    -
    +
    SQL execution - +

    In a previous section of the manual, we've seen how jOOQ can be used to that can be executed with any API including JDBC or ... jOOQ. This section of the manual deals with various means of actually executing SQL with jOOQ.

    @@ -6316,12 +6190,12 @@ fetch]]>

    The following sections of this manual will show how jOOQ is wrapping JDBC for SQL execution

    -
    +
    Comparison between jOOQ and JDBC - +

    Similarities with JDBC

    Even if there are , there are a lot of similarities between JDBC and jOOQ. Just to name a few: @@ -6343,29 +6217,28 @@ fetch]]>

  • : jOOQ does not formally distinguish between static statements and prepared statements. By default, all statements are prepared statements in jOOQ, internally. Executing a statement as a static statement can be done simply using a
  • : JDBC keeps open resources even if they are already consumed. With JDBC, there is a lot of verbosity around safely closing resources. In jOOQ, resources are closed after consumption, by default. If you want to keep them open after consumption, you have to explicitly say so.
  • -
    +
    Query vs. ResultQuery - +

    Unlike JDBC, jOOQ has a lot of knowledge about a SQL query's structure and internals (see the manual's section about ). Hence, jOOQ distinguishes between these two fundamental types of queries. While every can be executed, only can return results (see the manual's section about to learn more about fetching results). With plain SQL, the distinction can be made clear most easily:

    - resultQuery = create.resultQuery("SELECT * FROM BOOK"); -Result resultQuery.fetch();]]> -
    +Result resultQuery.fetch();]]>
    Fetching - +

    Fetching is something that has been completely neglegted by JDBC and also by various other database abstraction libraries. Fetching is much more than just looping or listing records or mapped objects. There are so many ways you may want to fetch data from a database, it should be considered a first-class feature of any database abstraction API. Just to name a few, here are some of jOOQ's fetching modes:

    @@ -6390,7 +6263,7 @@ Result resultQuery.fetch();]]> These modes of fetching are also documented in subsequent sections of the manual

    - fetch(); // The "standard" fetch when you know your query returns only one record @@ -6417,14 +6290,14 @@ List> fetchMany(); List fetch(RecordMapper mapper); // Execute a ResultQuery with jOOQ, but return a JDBC ResultSet, not a jOOQ object -ResultSet fetchResultSet();]]> +ResultSet fetchResultSet();]]>

    Fetch convenience

    These means of fetching are also available from and APIs

    - List fetch(Field field); List fetch(Field field, Class type); @@ -6458,14 +6331,14 @@ ResultSet fetchResultSet();]]> U fetchOne(int fieldIndex, Converter converter); Object fetchOne(String fieldName); T fetchOne(String fieldName, Class type); - U fetchOne(String fieldName, Converter converter);]]> + U fetchOne(String fieldName, Converter converter);]]>

    Fetch transformations

    These means of fetching are also available from and APIs

    - List fetchInto(Class type); // Transform your records into another table type - Result fetchInto(Table table);]]> + Result fetchInto(Table table);]]>

    Note, that apart from the methods, all fetch() methods will immediately close underlying JDBC result sets.

    -
    +
    Record vs. TableRecord - +

    jOOQ understands that SQL is much more expressive than Java, when it comes to the declarative typing of . As a declarative language, SQL allows for creating ad-hoc row value expressions (records with indexed columns, or tuples) and records (records with named columns). In Java, this is not possible to the same extent. Yet, still, sometimes you wish to use strongly typed records, when you know that you're selecting only from a single table

    @@ -6511,12 +6384,12 @@ ResultSet fetchResultSet();]]> When fetching data only from a single table, the type is known to jOOQ if you use jOOQ's to generate for your database tables. In order to fetch such strongly typed records, you will have to use the :

    - +System.out.println("Published in: " + book.getPublishedIn());]]>

    When you use the method, jOOQ will return the record type supplied with the argument table. Beware though, that you will no longer be able to use any clause that modifies the type of your . This includes: @@ -6525,17 +6398,17 @@ System.out.println("Published in: " + book.getPublishedIn());]]>

  • -
    +
    Record1 to Record{max-row-degree} - +

    jOOQ's support has been explained earlier in this manual. It is useful for constructing row value expressions where they can be used in SQL. The same typesafety is also applied to records for degrees up to {max-row-degree}. To express this fact, is extended by to . Apart from the fact that these extensions of the R type can be used throughout the , they also provide a useful API. Here is , for instance:

    - extends Record { + extends Record { // Access fields and values as row value expressions Row2 fieldsRow(); @@ -6548,23 +6421,23 @@ System.out.println("Published in: " + book.getPublishedIn());]]> // Access values by index T1 value1(); T2 value2(); -}]]> +}]]>

    Higher-degree records

    jOOQ chose to explicitly support degrees up to {max-row-degree} to match Scala's typesafe tuple, function and product support. Unlike Scala, however, jOOQ also supports higher degrees without the additional typesafety.

    -
    +
    Arrays, Maps and Lists - +

    By default, jOOQ returns an object, which is essentially a of . Often, you will find yourself wanting to transform this result object into a type that corresponds more to your specific needs. Or you just want to list all values of one specific column. Here are some examples to illustrate those use cases:

    - titles1 = create.select().from(BOOK).fetch().getValues(BOOK.TITLE); List titles2 = create.select().from(BOOK).fetch(BOOK.TITLE); String[] titles3 = create.select().from(BOOK).fetchArray(BOOK.TITLE); @@ -6584,22 +6457,22 @@ Map map4 = create.selectFrom(BOOK).fetchMap(BOOK.ID, BOOK.T Map> group1 = create.selectFrom(BOOK).fetch().intoGroups(BOOK.AUTHOR_ID); Map> group2 = create.selectFrom(BOOK).fetchGroups(BOOK.AUTHOR_ID); Map> group3 = create.selectFrom(BOOK).fetch().intoGroups(BOOK.AUTHOR_ID, BOOK.TITLE); -Map> group4 = create.selectFrom(BOOK).fetchGroups(BOOK.AUTHOR_ID, BOOK.TITLE);]]> +Map> group4 = create.selectFrom(BOOK).fetchGroups(BOOK.AUTHOR_ID, BOOK.TITLE);]]>

    Note that most of these convenience methods are available both through and , some are even available through as well.

    -
    +
    RecordHandler - +

    In a more functional operating mode, you might want to write callbacks that receive records from your select statement results in order to do some processing. This is a common data access pattern in Spring's JdbcTemplate, and it is also available in jOOQ. With jOOQ, you can implement your own classes and plug them into jOOQ's :

    - { Util.doThingsWithBook(book); }; ); -]]> +]]>

    See also the manual's section about the , which provides similar features

    -
    +
    RecordMapper - +

    In a more functional operating mode, you might want to write callbacks that map records from your select statement results in order to do some processing. This is a common data access pattern in Spring's JdbcTemplate, and it is also available in jOOQ. With jOOQ, you can implement your own classes and plug them into jOOQ's :

    - ids = create.selectFrom(BOOK) .orderBy(BOOK.ID) @@ -6655,17 +6528,17 @@ create.selectFrom(BOOK) create.selectFrom(BOOK) .orderBy(BOOK.ID) .fetch(book -> book.getId()); -]]> +]]>

    See also the manual's section about the , which provides similar features

    -
    +
    POJOs - +

    Fetching data in records is fine as long as your application is not really layered, or as long as you're still writing code in the DAO layer. But if you have a more advanced application architecture, you may not want to allow for jOOQ artefacts to leak into other layers. You may choose to write POJOs (Plain Old Java Objects) as your primary DTOs (Data Transfer Objects), without any dependencies on jOOQ's types, which may even potentially hold a reference to a , and thus a JDBC . Like Hibernate/JPA, jOOQ allows you to operate with POJOs. Unlike Hibernate/JPA, jOOQ does not "attach" those POJOs or create proxies with any magic in them.

    @@ -6678,7 +6551,7 @@ create.selectFrom(BOOK) jOOQ tries to find JPA annotations on your POJO types. If it finds any, they are used as the primary source for mapping meta-information. Only the annotation is used and understood by jOOQ. An example:

    - myBooks = create.select().from(BOOK).fetch().into(MyBook.class); -List myBooks = create.select().from(BOOK).fetchInto(MyBook.class);]]> +List myBooks = create.select().from(BOOK).fetchInto(MyBook.class);]]>

    Just as with any other JPA implementation, you can put the annotation on any class member, including attributes, setters and getters. Please refer to the Javadoc for more details. @@ -6701,7 +6574,7 @@ List myBooks = create.select().from(BOOK).fetchInto(MyBook.class);]]> - myBooks = create.select().from(BOOK).fetch().into(MyBook1.class); -List myBooks = create.select().from(BOOK).fetchInto(MyBook1.class);]]> +List myBooks = create.select().from(BOOK).fetchInto(MyBook1.class);]]>

    Please refer to the Javadoc for more details. @@ -6721,7 +6594,7 @@ List myBooks = create.select().from(BOOK).fetchInto(MyBook1.class);]]>< If jOOQ does not find any default constructor, columns are mapped to the "best-matching" constructor. This allows for using "immutable" POJOs with jOOQ. An example illustrates this:

    - myBooks = create.select(BOOK.ID, BOOK.AUTHOR_ID).from(BOOK).fetch().into(MyBook3.class); List myBooks = create.select(BOOK.ID, BOOK.AUTHOR_ID).from(BOOK).fetchInto(MyBook3.class); -]]> +]]>

    Please refer to the Javadoc for more details. @@ -6765,7 +6638,7 @@ List myBooks = create.select(BOOK.ID, BOOK.AUTHOR_ID).from(BOOK).fetchI jOOQ also allows for fetching data into abstract classes or interfaces, or in other words, "proxyable" types. This means that jOOQ will return a wrapped in a implementing your custom type. An example of this is given here:

    - myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetch().into(MyBook3.class); -List myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchInto(MyBook3.class);]]> +List myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchInto(MyBook3.class);]]>

    Please refer to the Javadoc for more details. @@ -6788,7 +6661,7 @@ List myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchInto( The above examples show how to fetch data into your own custom POJOs / DTOs. When you have modified the data contained in POJOs, you probably want to store those modifications back to the database. An example of this is given here:

    - +create.executeUpdate(book);]]>

    Note: Because of your manual setting of ID = 10, jOOQ's store() method will asume that you want to insert a new record. See the manual's section about for more details on this. @@ -6820,7 +6693,7 @@ create.executeUpdate(book);]]> If you're using jOOQ's , you can configure it to for you. Those DAOs operate on . An example of using such a DAO is given here:

    - +bookDao.delete(book);]]>

    More complex data structures

    jOOQ currently doesn't support more complex data structures, the way Hibernate/JPA attempt to map relational data onto POJOs. While future developments in this direction are not excluded, jOOQ claims that generic mapping strategies lead to an enormous additional complexity that only serves very few use cases. You are likely to find a solution using any of jOOQ's various , with only little boiler-plate code on the client side.

    -
    +
    Lazy fetching - +

    Unlike JDBC's , jOOQ's does not represent an open database cursor with various fetch modes and scroll modes, that needs to be closed after usage. jOOQ's results are simple in-memory Java objects, containing all of the result values. If your result sets are large, or if you have a lot of network latency, you may wish to fetch records one-by-one, or in small chunks. jOOQ supports a type for that purpose. In order to obtain such a reference, use the method. An example is given here:

    - cursor = null; try { @@ -6870,7 +6743,7 @@ finally { if (cursor != null) { cursor.close(); } -}]]> +}]]>

    As a holds an internal reference to an open , it may need to be closed at the end of iteration. If a cursor is completely scrolled through, it will conveniently close the underlying ResultSet. However, you should not rely on that. @@ -6886,16 +6759,16 @@ finally {

  • : You can use your own callbacks to map lazily fetched records.
  • : You can fetch data into your own custom POJO types.
  • -
    +
    Many fetching - +

    Many databases support returning several result sets, or cursors, from single queries. An example for this is Sybase ASE's sp_help command:

    - sp_help 'author' + sp_help 'author' +--------+-----+-----------+-------------+-------------------+ |Name |Owner|Object_type|Object_status|Create_date | @@ -6911,14 +6784,14 @@ finally { |last_name |varchar| 50|NULL| NULL| 0| |date_of_birth|date | 4|NULL| NULL| 1| |year_of_birth|int | 4|NULL| NULL| 1| -+-------------+-------+------+----+-----+-----+]]> ++-------------+-------+------+----+-----+-----+]]>

    The correct (and verbose) way to do this with JDBC is as follows:

    - +statement.close();]]>

    As previously discussed in the chapter about , jOOQ does not rely on an internal state of any JDBC object, which is "externalised" by Javadoc. Instead, it has a straight-forward API allowing you to do the above in a one-liner:

    -> results = create.fetchMany("sp_help 'author'");]]> +> results = create.fetchMany("sp_help 'author'");]]>

    Using generics, the resulting structure is immediately clear.

    -
    +
    Later fetching - +

    Some queries take very long to execute, yet they are not crucial for the continuation of the main program. For instance, you could be generating a complicated report in a Swing application, and while this report is being calculated in your database, you want to display a background progress bar, allowing the user to pursue some other work. This can be achived simply with jOOQ, by creating a , a type that extends . An example is given here:

    - future = create.selectFrom(BOOK).where(... complex predicates ...).fetchLater(); // This example actively waits for the result to be done @@ -6971,27 +6844,25 @@ while (!future.isDone()) { } // The result should be ready, now -Result result = future.get();]]> +Result result = future.get();]]>

    Note, that instead of letting jOOQ spawn a new thread, you can also provide jOOQ with your own :

    - future = create.selectFrom(BOOK).where(... complex predicates ...).fetchLater(service);]]> - -
    +FutureResult future = create.selectFrom(BOOK).where(... complex predicates ...).fetchLater(service);]]>
    ResultSet fetching - +

    When interacting with legacy applications, you may prefer to have jOOQ return a , rather than jOOQ's own types. This can be done simply, in two ways:

    - +rs2.close();]]>

    Transform jOOQ's Result into a JDBC ResultSet

    Instead of operating on a JDBC ResultSet holding an open resource from your database, you can also let jOOQ's wrap itself in a . The advantage of this is that the so-created ResultSet has no open connection to the database. It is a completely in-memory ResultSet:

    - result = create.selectFrom(BOOK).fetch(); -ResultSet rs = result.intoResultSet();]]> +ResultSet rs = result.intoResultSet();]]>

    The inverse: Fetch data from a legacy ResultSet using jOOQ

    The inverse of the above is possible too. Maybe, a legacy part of your application produces JDBC , and you want to turn them into a :

    - result = create.fetch(rs); // As a Cursor -Cursor cursor = create.fetchLazy(rs);]]> +Cursor cursor = create.fetchLazy(rs);]]>

    You can also tighten the interaction with jOOQ's data type system and features, by passing the record type to the above fetch methods:

    - result = create.fetch (rs, Integer.class, String.class); Cursor result = create.fetchLazy(rs, Integer.class, String.class); @@ -7038,22 +6909,22 @@ Cursor result = create.fetchLazy(rs, SQLDataType.INTEGER, SQLDataType.VA // Pass an array of fields: Result result = create.fetch (rs, BOOK.ID, BOOK.TITLE); -Cursor result = create.fetchLazy(rs, BOOK.ID, BOOK.TITLE);]]> +Cursor result = create.fetchLazy(rs, BOOK.ID, BOOK.TITLE);]]>

    If supplied, the additional information is used to override the information obtained from the 's

    -
    +
    Data type conversion - +

    Apart from a few extra features (), jOOQ only supports basic types as supported by the JDBC API. In your application, you may choose to transform these data types into your own ones, without writing too much boiler-plate code. This can be done using jOOQ's types. A converter essentially allows for two-way conversion between two Java data types <T> and <U>. By convention, the <T> type corresponds to the type in your database whereas the >U> type corresponds to your own user type. The Converter API is given here:

    - extends Serializable { + extends Serializable { /** * Convert a database object to a user object @@ -7074,7 +6945,7 @@ Cursor result = create.fetchLazy(rs, BOOK.ID, BOOK.TITLE);]]> * The user type */ Class toType(); -}]]> +}]]>

    Such a converter can be used in many parts of the jOOQ API. Some examples have been illustrated in the manual's section about . @@ -7085,7 +6956,7 @@ Cursor result = create.fetchLazy(rs, BOOK.ID, BOOK.TITLE);]]> Here is a some more elaborate example involving a Converter for :

    - { @Override @@ -7114,14 +6985,14 @@ public class CalendarConverter implements Converter dates1 = create.selectFrom(BOOK).fetch().getValues(BOOK.PUBLISHING_DATE, new CalendarConverter()); List dates2 = create.selectFrom(BOOK).fetch(BOOK.PUBLISHING_DATE, new CalendarConverter()); -]]> +]]>

    Enum Converters

    jOOQ ships with a built-in default , that you can use to map VARCHAR values to enum literals or NUMBER values to enum ordinals (both modes are supported). Let's say, you want to map a YES / NO / MAYBE column to a custom Enum:

    - +}]]>

    Using Converters in generated source code

    jOOQ also allows for generated source code to reference your own custom converters, in order to permanently replace a <T> type by your own, custom <U> type. See the manual's section about for details.

    -
    +
    Interning data - +

    SQL result tables are not optimal in terms of used memory as they are not designed to represent hierarchical data as produced by JOIN operations. Specifically, FOREIGN KEY values may repeat themselves unnecessarily:

    -+----+-----------+--------------+ ++----+-----------+--------------+ | ID | AUTHOR_ID | TITLE | +----+-----------+--------------+ | 1 | 1 | 1984 | | 2 | 1 | Animal Farm | | 3 | 2 | O Alquimista | | 4 | 2 | Brida | -+----+-----------+--------------+ ++----+-----------+--------------+

    Now, if you have millions of records with only few distinct values for AUTHOR_ID, you may not want to hold references to distinct (but equal) objects. This is specifically true for IDs of type or string representations thereof. jOOQ allows you to "intern" those values:

    - r1 = create.select(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE) .from(BOOK) .join(AUTHOR).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID)) @@ -7181,7 +7052,7 @@ Result r1 = create.select(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE) .from(BOOK) .join(AUTHOR).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID)) .intern(BOOK.AUTHOR_ID) - .fetch();]]> + .fetch();]]>

    You can specify as many fields as you want for interning. The above has the following effect: @@ -7199,14 +7070,14 @@ Result r1 = create.select(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE)

    Note, that jOOQ will not use interned data for identity comparisons: string1 == string2. Interning is used only to reduce the memory footprint of objects.

    -
    +
    Static statements vs. Prepared Statements - +

    With JDBC, you have full control over your SQL statements. You can decide yourself, if you want to execute a static without bind values, or a with (or without) bind values. But you have to decide early, which way to go. And you'll have to prevent SQL injection and syntax errors manually, when inlining your bind variables.

    @@ -7214,7 +7085,7 @@ Result r1 = create.select(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE) With jOOQ, this is easier. As a matter of fact, it is plain simple. With jOOQ, you can just set a flag in your , and all queries produced by that configuration will be executed as static statements, with all bind values inlined. An example is given here:

    - + r1 = create.select(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE) -- These statements are rendered by the two factories: SELECT ? FROM DUAL WHERE ? = ? -SELECT 1 FROM DUAL WHERE 1 = 1]]> - - +

    Reasons for choosing one or the other

    @@ -7248,12 +7118,12 @@ inlined.select(val(1)).where(val(1).equal(1)).fetch();]]>

    Note that you don't have to inline all your bind values at once. If you know that a bind value is not really a variable and should be inlined explicitly, you can do so by using , as documented in the manual's section about

    -
    +
    Reusing a Query's PreparedStatement - +

    As previously discussed in the chapter about , reusing PreparedStatements is handled a bit differently in jOOQ from how it is handled in JDBC

    @@ -7263,7 +7133,7 @@ inlined.select(val(1)).where(val(1).equal(1)).fetch();]]> With JDBC, you can easily reuse a by not closing it between subsequent executions. An example is given here:

    - +}]]>

    The above technique can be quite useful when you want to reuse expensive database resources. This can be the case when your statement is executed very frequently and your database would take non-negligible time to soft-parse the prepared statement and generate a new statement / cursor resource. @@ -7290,7 +7160,7 @@ finally { This is also modeled in jOOQ. However, the difference to JDBC is that closing a statement is the default action, whereas keeping it open has to be configured explicitly. This is better than JDBC, because the default action should be the one that is used most often. Keeping open statements is rarely done in average applications. Here's an example of how to keep open PreparedStatements with jOOQ:

    - query = create.selectOne().keepStatement(true); // Execute the query twice, against the same underlying PreparedStatement: @@ -7302,17 +7172,17 @@ try { // ... but now, you must not forget to close the query finally { query.close(); -}]]> +}]]>

    The above example shows how a query can be executed twice against the same underlying PreparedStatement. Unlike in other execution scenarios, you must not forget to close this query now

    -
    +
    Using JDBC batch operations - +

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

    @@ -7325,7 +7195,7 @@ finally {

    In code, this looks like the following snippet:

    - +int[] result = stmt.executeBatch();]]>

    This will also be supported by jOOQ

    @@ -7365,7 +7235,7 @@ int[] result = stmt.executeBatch();]]> jOOQ supports executing queries in batch mode as follows:

    - + .execute();]]>

    When creating a batch execution with a single query and multiple bind values, you will still have to provide jOOQ with dummy bind values for the original query. In the above example, these are set to null. For subsequent calls to bind(), there will be no type safety provided by jOOQ.

    -
    +
    Sequence execution - +

    Most databases support sequences of some sort, to provide you with unique values to be used for primary keys and other enumerations. If you're using jOOQ's , it will generate a sequence object per sequence for you. There are two ways of using such a sequence object:

    @@ -7401,34 +7271,34 @@ create.batch(create.insertInto(AUTHOR, ID, FIRST_NAME, LAST_NAME).values((Intege Instead of actually phrasing a select statement, you can also use the convenience methods:

    - +BigInteger currID = create.currval(S_AUTHOR_ID);]]>

    Inlining sequence references in SQL

    You can inline sequence references in jOOQ SQL statements. The following are examples of how to do that:

    - +]]>

    For more info about inlining sequence references in SQL statements, please refer to the manual's section about .

    -
    +
    Stored procedures and functions - +

    Many RDBMS support the concept of "routines", usually calling them procedures and/or functions. These concepts have been around in programming languages for a while, also outside of databases. Famous languages distinguishing procedures from functions are:

    @@ -7477,14 +7347,14 @@ create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) If you're using jOOQ's , it will generate objects for you. Let's consider the following example:

    - +

    The generated artefacts can then be used as follows:

    - +assertEquals(new BigDecimal("2"), procedure.getId();]]>

    But you can also call the procedure using a generated convenience method in a global Routines class:

    - +assertEquals(new BigDecimal("2"), procedure.getId();]]>

    For more details about for procedures, see the manual's section about . @@ -7516,31 +7386,30 @@ assertEquals(new BigDecimal("2"), procedure.getId();]]> Unlike procedures, functions can be inlined in SQL statements to generate or , if you're using . Assume you have a function like this:

    - +

    The generated artefacts can then be used as follows:

    - + - - +

    For more info about inlining stored function references in SQL statements, please refer to the manual's section about .

    -
    +
    Oracle Packages - +

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

    @@ -7554,17 +7423,17 @@ create.select(authorExists("Paulo")).fetchOne(0, boolean.class);]]>

    For more details about for procedures and packages see the manual's section about .

    -
    +
    Oracle member procedures - +

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

    - MEMBER FUNCTION counBOOKs RETURN NUMBER ) --- The type body is omitted for the example]]> +-- The type body is omitted for the example]]>

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

    - +assertNotNull(author.getLastName());]]>

    For more details about for UDTs see the manual's section about .

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

    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 the ). You can export any Result<Record> into the formats discussed in the subsequent chapters of the manual

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

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

    - + @@ -7636,86 +7503,79 @@ String xml = create.selectFrom(BOOK).fetch().formatXML(); Animal Farm -]]> +]]>

    The same result as an can be obtained using the Result.intoXML() method:

    -// Fetch books and format them as XML -Document xml = create.selectFrom(BOOK).fetch().intoXML(); +// Fetch books and format them as XML +Document xml = create.selectFrom(BOOK).fetch().intoXML();

    See the XSD schema definition here, for a formal definition of the XML export format:
    http://www.jooq.org/xsd/jooq-export-{export-xsd-version}.xsd

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

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

    -ID,AUTHOR_ID,TITLE +ID,AUTHOR_ID,TITLE 1,1,1984 -2,1,Animal Farm +2,1,Animal Farm

    In addition to the standard behaviour, you can also specify a separator character, as well as a special string to represent NULL values (which cannot be represented in standard CSV):

    -// Use ";" as the separator character +// Use ";" as the separator character String csv = create.selectFrom(BOOK).fetch().formatCSV(';'); // Specify "{null}" as a representation for NULL values -String csv = create.selectFrom(BOOK).fetch().formatCSV(';', "{null}"); - -
    +String csv = create.selectFrom(BOOK).fetch().formatCSV(';', "{null}");
    Exporting JSON - - -// Fetch books and format them as JSON -String json = create.selectFrom(BOOK).fetch().formatJSON(); + // Fetch books and format them as JSON +String json = create.selectFrom(BOOK).fetch().formatJSON();

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

    -{"fields":[{"name":"field-1","type":"type-1"}, +{"fields":[{"name":"field-1","type":"type-1"}, {"name":"field-2","type":"type-2"}, ..., {"name":"field-n","type":"type-n"}], "records":[[value-1-1,value-1-2,...,value-1-n], - [value-2-1,value-2-2,...,value-2-n]]} + [value-2-1,value-2-2,...,value-2-n]]}

    Note: This format has changed in jOOQ 2.6.0

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

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

    - + ID @@ -7735,76 +7595,72 @@ String html = create.selectFrom(BOOK).fetch().formatHTML(); Animal Farm -]]> - -
    +]]>
    Exporting Text - - -// Fetch books and format them as text -String text = create.selectFrom(BOOK).fetch().format(); + // Fetch books and format them as text +String text = create.selectFrom(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| -+---+---------+-----------+ ++---+---------+-----------+

    A simple text representation can also be obtained by calling toString() on a Result object. See also the manual's section about

    -
    +
    Importing data - +

    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 the formats described in the subsequent sections of this manual.

    -
    +
    Importing CSV - +

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

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

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

    -DSLContext create = DSL.using(connection, dialect); +DSLContext create = DSL.using(connection, dialect); // Load data into the AUTHOR table from an input stream // holding the CSV data. create.loadInto(AUTHOR) .loadCSV(inputstream) .fields(ID, AUTHOR_ID, TITLE) - .execute(); + .execute();

    Here are various other examples:

    -// Ignore the AUTHOR_ID column from the CSV file when inserting +// Ignore the AUTHOR_ID column from the CSV file when inserting create.loadInto(AUTHOR) .loadCSV(inputstream) .fields(ID, null, TITLE) @@ -7845,13 +7701,13 @@ create.loadInto(AUTHOR) .loadCSV(inputstream) .fields(ID, null, TITLE) - .execute(); + .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(); + loader = /* .. */ .execute(); // The number of processed rows int processed = loader.processed(); @@ -7874,23 +7730,21 @@ int rowIndex = error.rowIndex(); String[] row = error.row(); // The query that caused the error -Query query = error.query();]]> - -
    +Query query = error.query();]]>
    Importing XML - +

    This is not yet supported

    -
    +
    CRUD with UpdatableRecords - +

    Your database application probably consists of 50% - 80% CRUD, whereas only the remaining 20% - 50% of querying is actual querying. Most often, you will operate on records of tables without using any advanced relational concepts. This is called CRUD for

    @@ -7909,35 +7763,35 @@ Query query = error.query();]]> In normalised databases, every table has a primary key by which a tuple/record within that table can be uniquely identified. In simple cases, this is a (possibly auto-generated) number called ID. But in many cases, primary keys include several non-numeric columns. An important feature of such keys is the fact that in most databases, they are enforced using an index that allows for very fast random access to the table. A typical way to access / modify / delete a book is this:

    - +DELETE FROM BOOK WHERE ID = 5;]]>

    Normalised databases assume that a primary key is unique "forever", i.e. that a key, once inserted into a table, will never be changed or re-inserted after deletion. In order to use jOOQ's operations correctly, you should design your database accordingly.

    -
    +
    Simple CRUD - +

    If you're using jOOQ's , it will generate implementations for every table that has a primary key. When such a record form the database, these records are "attached" to the that created them. This means that they hold an internal reference to the same database connection that was used to fetch them. This connection is used internally by any of the following methods of the UpdatableRecord:

    - +int delete() throws DataAccessException;]]>

    See the manual's section about for some more insight on "attached" objects. @@ -7948,7 +7802,7 @@ int delete() throws DataAccessException;]]> Storing a record will perform an or an . In general, new records are always inserted, whereas records loaded from the database are always updated. This is best visualised in code:

    - +book2.store();]]>

    Some remarks about storing: @@ -7984,11 +7838,11 @@ book2.store();]]> Deleting a record will remove it from the database. Here's how you delete records:

    - +book.delete();]]>

    Refreshing

    @@ -7998,31 +7852,30 @@ book.delete();]]> In order to perform a refresh, use the following Java code:

    - +book.refresh();]]>

    CRUD and SELECT statements

    CRUD operations can be combined with regular querying, if you select records from single database tables, as explained in the manual's section about . For this, you will need to use the selectFrom() method from the :

    - -
    +}]]>
    Records' internal flags - +

    All of jOOQ's maintain an internal state for every column value. This state is composed of three elements:

    @@ -8035,34 +7888,34 @@ for (BookRecord book : create.fetch(BOOK, BOOK.PUBLISHED_IN.equal(1948))) {

    The purpose of the above information is for jOOQ's to know, which values need to be stored to the database, and which values have been left untouched.

    -
    +
    IDENTITY values - +

    Many databases support the concept of IDENTITY values, or key values. This is reflected by JDBC's method. jOOQ abstracts using this method as many databases and JDBC drivers behave differently with respect to generated keys. Let's assume the following SQL Server BOOK table:

    - +)]]>

    If you're using jOOQ's , the above table will generate a with an IDENTITY column. This information is used by jOOQ internally, to update IDs after calling :

    - +System.out.println(book.getId());]]>

    Database compatibility

    @@ -8071,8 +7924,8 @@ System.out.println(book.getId());]]>

    These SQL dialects implement the standard very neatly.

    - +

    H2, MySQL, Postgres, SQL Server, Sybase ASE, Sybase SQL Anywhere @@ -8080,7 +7933,7 @@ id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1)]]>

    These SQL dialects implement identites, but the DDL syntax doesn’t follow the standard

    - +id INTEGER NOT NULL IDENTITY]]>

    Oracle @@ -8104,7 +7957,7 @@ id INTEGER NOT NULL IDENTITY]]>

    Oracle does not know any identity columns at all. Instead, you will have to use a trigger and update the ID column yourself, using a custom sequence. Something along these lines:

    - +END my_trigger;]]>

    Note, that this approach can be employed in most databases supporting sequences and triggers! It is a lot more flexible than standard identities

    -
    +
    Non-updatable records - +

    Tables without a PRIMARY KEY are considered non-updatable by jOOQ, as jOOQ has no way of uniquely identifying such a record within the database. If you're using jOOQ's , such tables will generate classes, instead of classes. When you fetch from such a table, the returned records will not allow for calling any of the methods.

    @@ -8164,12 +8016,12 @@ List books = author.fetchChildren(FK_BOOK_AUTHOR);]]>

    Note, that some databases use internal rowid or object-id values to identify such records. jOOQ does not support these vendor-specific record meta-data.

    -
    +
    Optimistic locking - +

    jOOQ allows you to perform operations using optimistic locking. You can immediately take advantage of this feature by activating the relevant . Without any further knowledge of the underlying data semantics, this will have the following impact on store() and delete() methods:

    @@ -8184,7 +8036,7 @@ List books = author.fetchChildren(FK_BOOK_AUTHOR);]]> The above changes to jOOQ's behaviour are transparent to the API, the only thing you need to do for it to be activated is to set the Settings flag. Here is an example illustrating optimistic locking:

    - +book2.store();]]>

    Optimised optimistic locking using TIMESTAMP fields

    If you're using jOOQ's , you can take indicate TIMESTAMP or UPDATE COUNTER fields for every generated table in the . Let's say we have this table:

    - +)]]>

    The MODIFIED column will contain a timestamp indicating the last modification timestamp for any book in the BOOK table. If you're using jOOQ and it's , jOOQ will then generate this TIMESTAMP value for you, automatically. However, instead of running an additional statement prior to an UPDATE or DELETE statement, jOOQ adds a WHERE-clause to the UPDATE or DELETE statement, checking for TIMESTAMP's integrity. This can be best illustrated with an example:

    - +book2.store();]]>

    As before, without the added TIMESTAMP column, optimistic locking is transparent to the API. @@ -8247,17 +8099,17 @@ book2.store();]]>

    Note, for explicit pessimistic locking, please consider the manual's section about the . For more details about how to configure TIMESTAMP or VERSION fields, consider the manual's section about .

    -
    +
    Batch execution - +

    When inserting, updating, deleting a lot of records, you may wish to profit from JDBC batch operations, which can be performed by jOOQ. These are available through jOOQ's as shown in the following example:

    - books = create.fetch(BOOK); // Modify the above books, and add some new ones: @@ -8265,24 +8117,24 @@ modify(books); addMore(books); // Batch-update and/or insert all of the above books -create.batchStore(books);]]> +create.batchStore(books);]]>

    Internally, jOOQ will render all the required SQL statements and execute them as a regular .

    -
    +
    DAOs - +

    If you're using jOOQ's , you can configure it to generate and DAOs for you. jOOQ then generates one DAO per , i.e. per table with a single-column primary key. Generated DAOs implement a common jOOQ type called . This type contains the following methods:

    - corresponds to the DAO's related table + corresponds to the DAO's related table //

    corresponds to the DAO's related generated POJO type // corresponds to the DAO's related table's primary key type. // Note that multi-column primary keys are not yet supported by DAOs @@ -8318,13 +8170,13 @@ public interface DAO, P, T> { // These methods provide DAO meta-information Table getTable(); Class

    getType(); -}]]> +}]]>

    Besides these base methods, generated DAO classes implement various useful fetch methods. An incomplete example is given here, for the BOOK table:

    - { // Columns with primary / unique keys produce fetchOne() methods @@ -8333,12 +8185,12 @@ public class BookDao extends DAOImpl { // Other columns produce fetch() methods, returning several records public List fetchByAuthorId(Integer... values) { ... } public List fetchByTitle(String... values) { ... } -}]]> +}]]>

    Note that you can further subtype those pre-generated DAO classes, to add more useful DAO methods to them. Using such a DAO is simple:

    - - -
    +bookDao.delete(book);]]>
    Exception handling - +

    Checked vs. unchecked exceptions

    This is an eternal and religious debate. Pros and cons have been discussed time and again, and it still is a matter of taste, today. In this case, jOOQ clearly takes a side. jOOQ's exception strategy is simple: @@ -8393,12 +8243,12 @@ bookDao.delete(book);]]>

    The following section about documents means of overriding jOOQ's exception handling, if you wish to deal separately with some types of constraint violations, or if you raise business errors from your database, etc.

    -
    +
    ExecuteListeners - +

    The lets you specify a list of instances. 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, triggers, etc. Advanced ExecuteListeners can also provide custom implementations of Connection, PreparedStatement and ResultSet to jOOQ in apropriate methods.

    @@ -8409,7 +8259,7 @@ bookDao.delete(book);]]> Here is a sample implementation of an ExecuteListener, that is simply counting the number of queries per type that are being executed using jOOQ:

    - +}]]>

    Now, configure jOOQ's runtime to load your listener

    - +DSLContext create = DSL.using(configuration);]]>

    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 - 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 +15:16:52,983 INFO - OTHER : 30 executions

    Please read the for more details @@ -8473,7 +8323,7 @@ for (ExecuteType type : ExecuteType.values()) { The following depicts an example of a custom ExecuteListener, which pretty-prints all queries being executed by jOOQ to stdout:

    - +}]]>

    See also the manual's sections about and the for more sample implementations of actual ExecuteListeners.

    -
    +
    Database meta data - +

    Since jOOQ 3.0, a simple wrapping API has been added to wrap JDBC's rather awkward

    -
    +
    Logging - +

    jOOQ logs all SQL queries and fetched result sets to its internal DEBUG logger, which is implemented as an . By default, execute logging is activated in the . In order to see any DEBUG log output, put either log4j or slf4j on jOOQ's classpath along with their respective configuration. A sample log4j configuration can be seen here:

    - + @@ -8544,20 +8394,20 @@ public class PrettyPrinter extends DefaultExecuteListener { -]]> +]]>

    With the above configuration, let's fetch some data with jOOQ

    - +

    The above query may result in the following log output:

    - with bind values : select "BOOK"."ID", "BOOK"."TITLE" from "BOOK" order by "BOOK"."ID" asc, limit 2 offset 1 Query executed : Total: 1.439ms Fetched result : +----+------------+ @@ -8567,7 +8417,7 @@ Fetched result : +----+------------+ : | 3|O Alquimista| : +----+------------+ Finishing : Total: 4.814ms, +3.375ms -]]> +]]>

    Essentially, jOOQ will log @@ -8583,12 +8433,12 @@ Finishing : Total: 4.814ms, +3.375ms

    If you wish to use your own logger (e.g. avoiding printing out sensitive data), you can deactivate jOOQ's logger using and implement your own .

    -
    +
    Performance considerations - +

    Many users may have switched from higher-level abstractions such as Hibernate to jOOQ, because of Hibernate's difficult-to-manage performance, when it comes to large database schemas and complex second-level caching strategies. However, jOOQ itself is not a lightweight database abstraction framework, and it comes with its own overhead. Please be sure to consider the following points:

    @@ -8603,14 +8453,14 @@ Finishing : Total: 4.814ms, +3.375ms

    Don't be put off by the above paragraphs. You should optimise wisely, i.e. only in places where you really need very high throughput to your database. jOOQ's overhead compared to plain JDBC is typically less than 1ms per query.

    -
    +
    Code generation - +

    While optional, source code generation is one of jOOQ's main assets if you wish to increase developer productivity. jOOQ's code generator takes your database schema and reverse-engineers it into a set of Java classes modelling , , , , , , user-defined types and many more.

    @@ -8624,12 +8474,12 @@ Finishing : Total: 4.814ms, +3.375ms

    The following chapters will show how to configure the code generator and how to generate various artefacts.

    -
    +
    Configuration and setup of the generator - +

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

    @@ -8656,7 +8506,7 @@ Finishing : Total: 4.814ms, +3.375ms You need to tell jOOQ some things about your database connection. Here's an example of how to do it for an Oracle database

    - + @@ -8730,7 +8580,7 @@ Finishing : Total: 4.814ms, +3.375ms [/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 for a formal specification at:
    @@ -8742,7 +8592,7 @@ Finishing : Total: 4.814ms, +3.375ms Code generation works by calling this class with the above property file as argument.

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

    Be sure that these elements are located on the classpath: @@ -8810,20 +8660,20 @@ Finishing : Total: 4.814ms, +3.375ms 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 @@ -8875,7 +8725,7 @@ Finishing : Total: 4.814ms, +3.375ms -]]> +]]>

    See the full example of a pom.xml including the jOOQ-codegen artefact here:
    @@ -8887,17 +8737,17 @@ Finishing : Total: 4.814ms, +3.375ms

    Be sure, both jooq-{jooq-version}.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.

    -
    +
    Advanced generator configuration - +

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

    - + @@ -8909,13 +8759,13 @@ Finishing : Total: 4.814ms, +3.375ms org.jooq.util.DefaultGeneratorStrategy -]]> +]]>

    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:

    - +}]]>

    More examples can be found here: @@ -9036,7 +8886,7 @@ public class AsInDatabaseStrategy extends DefaultGeneratorStrategy { Within the <generator/> element, there are other configuration elements:

    - + ... -]]> +]]>

    Check out the some of the manual's "advanced" sections to find out more about the advanced configuration parameters. @@ -9098,7 +8948,7 @@ public class AsInDatabaseStrategy extends DefaultGeneratorStrategy { Also, you can add some optional advanced configuration parameters for the generator:

    - + true -]]> +]]>

    Property interdependencies

    @@ -9179,12 +9029,12 @@ public class AsInDatabaseStrategy extends DefaultGeneratorStrategy {

  • When daos = true, then jOOQ will set pojos = true
  • When immutablePojos = true, then jOOQ will set pojos = true
  • -
    +
    Generated global artefacts - +

    For increased convenience at the use-site, jOOQ generates "global" artefacts at the code generation root location, referencing tables, routines, sequences, etc. In detail, these global artefacts include the following:

    @@ -9201,7 +9051,7 @@ public class AsInDatabaseStrategy extends DefaultGeneratorStrategy { When referencing global artefacts from your client application, you would typically static import them as such:

    - -
    + .values(com.example.generated.Sequences.MY_SEQUENCE.nextval(), com.example.generated.Routines.myFunction())]]>
    Generated tables - +

    Every table in your database will generate a implementation that looks like this:

    - { + { // The singleton instance public static final Book BOOK = new Book(); @@ -9240,7 +9089,7 @@ create.insertInto(com.example.generated.Tables.MY_TABLE) } // [...] -}]]> +}]]>

    Flags influencing generated tables

    @@ -9260,17 +9109,17 @@ create.insertInto(com.example.generated.Tables.MY_TABLE)

    Table generation cannot be deactivated

    -
    +
    Generated records - +

    Every table in your database will generate a implementation that looks like this:

    - @@ -9311,7 +9160,7 @@ implements IBook { } // [...] -}]]> +}]]>

    Flags influencing generated records

    @@ -9331,17 +9180,17 @@ implements IBook {

    Record generation can be deactivated using the records flag

    -
    +
    Generated POJOs - +

    Every table in your database will generate a POJO implementation that looks like this:

    - +}]]>

    Flags influencing generated POJOs

    @@ -9394,24 +9243,24 @@ public class Book implements java.io.Serializable

    POJO generation can be activated using the pojos flag

    -
    +
    Generated Interfaces - +

    Every table in your database will generate an interface that looks like this:

    - +}]]>

    Flags influencing generated interfaces

    @@ -9426,18 +9275,18 @@ public class Book implements java.io.Serializable

    POJO generation can be activated using the interfaces flag

    -
    +
    Generated DAOs - +

    Generated DAOs

    Every table in your database will generate a implementation that looks like this:

    - { + { // Generated constructors public BookDao() { @@ -9462,43 +9311,43 @@ public class Book implements java.io.Serializable } // [...] -}]]> +}]]>

    Flags controlling DAO generation

    DAO generation can be activated using the daos flag

    -
    +
    Generated sequences - +

    Every sequence in your database will generate a implementation that looks like this:

    - S_AUTHOR_ID = new SequenceImpl("S_AUTHOR_ID", TEST, SQLDataType.INTEGER); -}]]> +}]]>

    Flags controlling sequence generation

    Sequence generation cannot be deactivated

    -
    +
    Generated procedures - +

    Every procedure or function (routine) in your database will generate a implementation that looks like this:

    - { + { // All IN, IN OUT, OUT parameters and function return values generate a static member public static final Parameter AUTHOR_NAME = createParameter("AUTHOR_NAME", SQLDataType.VARCHAR); @@ -9523,7 +9372,7 @@ public class Book implements java.io.Serializable } // [...] -}]]> +}]]>

    Package and member procedures or functions

    @@ -9534,17 +9383,17 @@ public class Book implements java.io.Serializable

    Routine generation cannot be deactivated

    -
    +
    Generated UDTs - +

    Every UDT in your database will generate a implementation that looks like this:

    - { + { // The singleton UDT instance public static final UAddressType U_ADDRESS_TYPE = new UAddressType(); @@ -9558,13 +9407,13 @@ public class Book implements java.io.Serializable createField("COUNTRY", SQLDataType.VARCHAR, U_ADDRESS_TYPE); // [...] -}]]> +}]]>

    Besides the implementation, a implementation is also generated

    - { + { // Every attribute generates a getter and a setter @@ -9576,24 +9425,24 @@ public class Book implements java.io.Serializable public String getCountry() {...} // [...] -}]]> +}]]>

    Flags controlling UDT generation

    UDT generation cannot be deactivated

    -
    +
    Custom data types and type conversion - +

    When using a custom type in jOOQ, you need to let jOOQ know about its associated . Ad-hoc usages of such converters has been discussed in the chapter about . 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_

    - + @@ -9616,41 +9465,39 @@ public class Book implements java.io.Serializable .*\.DATE_OF_.* -]]> +]]>

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

    - { + { // [...] public final TableField DATE_OF_BIRTH = // [...] // [...] -}]]> +}]]>

    This means that the bound type 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(AUTHOR) .where(AUTHOR.DATE_OF_BIRTH.greaterThan(new GregorianCalendar(1980, 0, 1))) - .fetch(AUTHOR.DATE_OF_BIRTH);]]> - -
    + .fetch(AUTHOR.DATE_OF_BIRTH);]]>
    Mapping generated schemata and tables - +

    We've seen previously in the chapter about , that schemata and tables can be mapped at runtime to other names. But 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 @@ -9658,14 +9505,12 @@ create.selectFrom(AUTHOR) PROD -]]> - -
    +]]>
    Code generation for large schemas - +

    Databases can become very large in real-world applications. This is not a problem for jOOQ's code generator, but it can be for the Java compiler. jOOQ generates some classes for . These classes can hit two sorts of limits of the compiler / JVM:

    @@ -9685,23 +9530,23 @@ create.selectFrom(AUTHOR)
  • to avoid generating using <globalObjectReferences/>
  • Remove uncompilable classes after code generation
  • -
    +
    Tools - +

    These chapters hold some information about tools to be used with jOOQ

    -
    +
    JDBC mocking for unit testing - +

    When writing unit tests for your data access layer, you have probably used some generic mocking tool offered by popular providers like Mockito, jmock, mockrunner, or even DBUnit. With jOOQ, you can take advantage of the built-in JDBC mock API that allows you to simulate a database on the JDBC level for precisely those SQL/JDBC use cases supported by jOOQ.

    @@ -9728,7 +9573,7 @@ create.selectFrom(AUTHOR) This work is greatly simplified, when using jOOQ's own mock API. The org.jooq.tools.jdbc package contains all the essential implementations for both JDBC 4.0 and 4.1, which are needed to mock JDBC for jOOQ. In order to write mock tests, provide the jOOQ with a , and implement the :

    - result = create.selectFrom(BOOK).where(BOOK.ID.equal(5)).fetch();]]> +Result result = create.selectFrom(BOOK).where(BOOK.ID.equal(5)).fetch();]]>

    As you can see, the configuration setup is simple. Now, the MockDataProvider acts as your single point of contact with JDBC / jOOQ. It unifies any of these execution modes, transparently: @@ -9760,7 +9605,7 @@ Result result = create.selectFrom(BOOK).where(BOOK.ID.equal(5)).fetc Now, here's how to implement MockDataProvider:

    - result = create.selectFrom(BOOK).where(BOOK.ID.equal(5)).fetc return mock; } -}]]> +}]]>

    Essentially, the contains all the necessary information for you to decide, what kind of data you should return. The wraps up two pieces of information: @@ -9812,12 +9657,12 @@ Result result = create.selectFrom(BOOK).where(BOOK.ID.equal(5)).fetc

    See the for a list of rules that you should follow.

    -
    +
    jOOQ Console - +

    The 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:

    @@ -9857,19 +9702,19 @@ Result result = create.selectFrom(BOOK).where(BOOK.ID.equal(5)).fetc Both modes will require that you set the in the Configuration:

    - +DSLContext create = DSL.using(configuration);]]>

    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: @@ -9930,36 +9775,36 @@ catch (Exception ignore) {} 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 +// Create a new RemoteDebuggerServer in your application that listens to // incoming connections on a given port -SERVER = new RemoteDebuggerServer(DEBUGGER_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-{jooq-version}.jar [host] [port] +java -jar jooq-console-{jooq-version}.jar [host] [port]

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

    -
    +
    Reference - +

    These chapters hold some general jOOQ reference information

    -
    +
    Supported RDBMS - +

    A list of supported databases

    Every RDMBS out there has its own little specialties. jOOQ considers those specialties as much as possible, while trying to standardise the behaviour in jOOQ. In order to increase the quality of jOOQ, some 70 unit tests are run for syntax and variable binding verification, as well as some 180 integration tests with an overall of around 1200 queries for any of these databases: @@ -10018,12 +9863,12 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);

    This section will soon contain a feature matrix, documenting what feature is available for which database.

    -
    +
    Data types - +

    There is always a small mismatch between SQL data types and Java data types. This is for two reasons:

    @@ -10034,21 +9879,21 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);

    This chapter should document the most important notes about SQL, JDBC and jOOQ data types.

    -
    +
    BLOBs and CLOBs - +

    jOOQ currently doesn't explicitly support JDBC BLOB and CLOB data types. If you use any of these data types in your database, jOOQ will map them to byte[] and String instead. In simple cases (small data), this simplification is sufficient. In more sophisticated cases, you may have to bypass jOOQ, in order to deal with these data types and their respective resources. True support for LOBs is on the roadmap, though.

    -
    +
    Unsigned integer types - +

    Some databases explicitly support unsigned integer data types. In most normal JDBC-based applications, they would just be mapped to their signed counterparts letting bit-wise shifting and tweaking to the user. jOOQ ships with a set of unsigned implementations modelling the following types:

    @@ -10067,12 +9912,12 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);
  • UInteger wraps
  • ULong wraps
  • -
    +
    INTERVAL data types - +

    jOOQ fills a gap opened by JDBC, which neglects an important SQL data type as defined by the SQL standards: INTERVAL types. SQL knows two different types of intervals:

    @@ -10097,51 +9942,51 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);
  • INTERVAL * or / NUMERIC => INTERVAL
  • NUMERIC * INTERVAL => INTERVAL
  • -
    +
    XML data types - +

    XML data types are currently not supported

    -
    +
    Geospacial data types - +

    Geospacial data types

    Geospacial data types are currently not supported

    -
    +
    CURSOR data types - +

    Some databases support cursors returned from stored procedures. They are mapped to the following jOOQ data type:

    -> cursor;]]> +> cursor;]]>

    In fact, such a cursor will be fetched immediately by jOOQ and wrapped in an object.

    -
    +
    ARRAY and TABLE data types - +

    The SQL standard specifies ARRAY data types, that can be mapped to Java arrays as such:

    - intArray;]]> + intArray;]]>

    The above array type is supported by these SQL dialects: @@ -10156,23 +10001,23 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);

    Oracle has strongly-typed arrays and table types (as opposed to the previously seen anonymously typed arrays). These arrays are wrapped by types.

    -
    +
    jOOQ's BNF pseudo-notation - +

    This chapter will soon contain an overview over jOOQ's API using a pseudo BNF notation.

    -
    +
    Quality Assurance - +

    jOOQ is running some of your most mission-critical logic: the interface layer between your Java / Scala application and the database. You have probably chosen jOOQ for any of the following reasons:

    @@ -10212,7 +10057,7 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT); jOOQ is used in jOOQ-meta as a proof of concept. This includes complex queries such as the following Postgres query

    - +}]]>

    These rather complex queries show that the jOOQ API is fit for advanced SQL use-cases, compared to the rather simple, often unrealistic queries in the integration test suite.

    @@ -10275,12 +10120,12 @@ for (Record record : create().select(

    Keeping things DRY leads to longer stack traces, but in turn, also increases the relevance of highly reusable code-blocks. Chances that some parts of the jOOQ code base slips by integration test coverage decrease significantly.

    -
    +
    Migrating to jOOQ 3.0 - +

    This section is for all users of jOOQ 2.x who wish to upgrade to the next major release. In the next sub-sections, the most important changes are explained. Some code hints are also added to help you fix compilation errors.

    @@ -10304,13 +10149,13 @@ for (Record record : create().select( Some hints related to row value expressions:

    - record = create.select(BOOK.TITLE, BOOK.ID).from(BOOK).where(ID.eq(1)).fetchOne(); Result> result = create.select(BOOK.TITLE, BOOK.ID).from(BOOK).fetch(); // But Record2 extends Record. You don't have to use the additional typesafety: Record record = create.select(BOOK.TITLE, BOOK.ID).from(BOOK).where(ID.eq(1)).fetchOne(); -Result result = create.select(BOOK.TITLE, BOOK.ID).from(BOOK).fetch();]]> +Result result = create.select(BOOK.TITLE, BOOK.ID).from(BOOK).fetch();]]>

    SelectQuery and SelectXXXStep are now generic

    @@ -10336,7 +10181,7 @@ Result result = create.select(BOOK.TITLE, BOOK.ID).from(BOOK).fetch();]]> - + ).fetch(); // Execute the "attached" query]]>

    Quantified comparison predicates

    Field.equalAny(...) and similar methods have been removed in favour of Field.equal(any(...)). This greatly simplified the Field API. An example:

    -> subselect = any(select(BOOK.ID).from(BOOK)); -Condition condition = BOOK.ID.equal(subselect);]]> +Condition condition = BOOK.ID.equal(subselect);]]>

    FieldProvider

    @@ -10372,7 +10217,7 @@ Condition condition = BOOK.ID.equal(subselect);]]> GroupField has been introduced as a DSL marker interface to denote fields that can be passed to GROUP BY clauses. This includes all org.jooq.Field types. However, fields obtained from ROLLUP(), CUBE(), and GROUPING SETS() functions no longer implement Field. Instead, they only implement GroupField. An example:

    - field1a = Factory.rollup(...); // OK Field field2a = Factory.one(); // OK @@ -10380,7 +10225,7 @@ Field field2a = Factory.one(); // OK GroupField field1b = DSL.rollup(...); // OK Field field1c = DSL.rollup(...); // Compilation error GroupField field2b = DSL.one(); // OK -Field field2c = DSL.one(); // OK]]> +Field field2c = DSL.one(); // OK]]>

    NULL predicate

    @@ -10398,14 +10243,14 @@ Field field2c = DSL.one(); // OK]]> Here is an example how to check if a field has a given value, without applying SQL's ternary NULL logic:

    - +Condition condition3 = BOOK.TITLE.isNotDistinctFrom(possiblyNull);]]>

    Configuration

    @@ -10426,14 +10271,14 @@ Condition condition3 = BOOK.TITLE.isNotDistinctFrom(possiblyNull);]]> In order to allow for simpler connection / data source management, jOOQ externalised connection handling in a new ConnectionProvider type. The previous two connection modes are maintained backwards-compatibly (JDBC standalone connection mode, pooled DataSource mode). Other connection modes can be injected using:

    - +}]]>

    These are some side-effects of the above change @@ -10483,7 +10328,7 @@ Condition condition3 = BOOK.TITLE.isNotDistinctFrom(possiblyNull);]]>

  • The UpdatableTable type has been removed. While adding significant complexity to the type hierarchy, this type adds not much value over a simple Table.getPrimaryKey() != null check.
  • The USE statement support has been removed from jOOQ. Its behaviour was ill-defined, while it didn't work the same way (or didn't work at all) in some databases.
  • -
    +
    -]]> - - + +]]>

    These are useful to provide examples in code. Often, with jOOQ, it is even more useful to compare SQL code with its corresponding Java/jOOQ code. When this is done, the blocks are aligned side-by-side, with SQL usually being on the left, and Java usually being on the right:

    - + - - +

    Code block contents

    @@ -331,13 +324,11 @@ create.selectOne()]]>

    - - - +DSLContext create = DSL.using(connection, SQLDialect.ORACLE);]]>

    Your naming may differ, of course. For instance, you could name the "create" instance "db", instead. @@ -368,16 +359,16 @@ DSLContext create = DSL.using(connection, SQLDialect.ORACLE);]]>

    jOOQ query examples run against the sample database. See the manual's section about to learn more about the sample database.

    - +
    The sample database used in this manual - +

    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 language ( +CREATE TABLE language ( id NUMBER(7) NOT NULL PRIMARY KEY, cd CHAR(2) NOT NULL, description VARCHAR2(50) @@ -415,16 +406,16 @@ CREATE TABLE book_to_book_store ( PRIMARY KEY(name, book_id), CONSTRAINT fk_b2bs_book_store FOREIGN KEY (name) REFERENCES book_store (name) ON DELETE CASCADE, CONSTRAINT fk_b2bs_book FOREIGN KEY (book_id) REFERENCES 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

    -
    +
    Different use cases for jOOQ - +

    jOOQ has originally been created as a library for complete abstraction of JDBC and all database interaction. Various best practices that are frequently encountered in pre-existing software products are applied to this library. This includes:

    @@ -453,23 +444,23 @@ CREATE TABLE book_to_book_store (

    The following sections explain about various use cases for using jOOQ in your application.

    -
    +
    jOOQ as a SQL builder - +

    This is the most simple of all use cases, allowing for construction of valid SQL for any database. In this use case, you will not use and probably not even . Instead, you'll use jOOQ to wrap strings, literals and other user-defined objects into an object-oriented, type-safe AST modelling your SQL statements. An example is given here:

    - + .getSQL();]]>

    The SQL string that you can generate as such can then be executed using JDBC directly, using Spring's JdbcTemplate, using Apache DbUtils and many other tools. @@ -481,23 +472,23 @@ String sql = create.select(fieldByName("BOOK","TITLE"), fieldByName("AUTHOR","FI

  • : This section contains a lot of information about creating SQL statements using the jOOQ API
  • : This section contains information useful in particular to those that want to supply , , etc. as plain SQL to jOOQ, rather than through generated artefacts
  • -
    +
    jOOQ as a SQL builder with code generation - +

    In addition to using jOOQ as a , you can also use jOOQ's code generation features in order to compile your SQL statements using a Java compiler against an actual database schema. This adds a lot of power and expressiveness to just simply constructing SQL using custom strings and literals, as you can be sure that all database artefacts actually exist in the database, and that their type is correct. An example is given here:

    - + .getSQL();]]>

    The SQL string that you can generate as such can then be executed using JDBC directly, using Spring's JdbcTemplate, using Apache DbUtils and many other tools. @@ -509,30 +500,30 @@ String sql = create.select(BOOK.TITLE, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)

  • : This section contains a lot of information about creating SQL statements using the jOOQ API
  • : This section contains the necessary information to run jOOQ's code generator against your developer database
  • -
    +
    jOOQ as a SQL executor - +

    Instead of any tool mentioned in the previous chapters, you can also use jOOQ directly to execute your jOOQ-generated SQL statements. This will add a lot of convenience on top of the previously discussed API for typesafe SQL construction, when you can re-use the information from generated classes to fetch records and custom data types. An example is given here:

    -> result = create.select(BOOK.TITLE, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .from(BOOK) .join(AUTHOR) .on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)) .where(BOOK.PUBLISHED_IN.equal(1948)) - .fetch();]]> + .fetch();]]>

    jOOQ doesn't stop here, though! You can execute any SQL with jOOQ. In other words, you can use any other SQL building tool and run the SQL statements with jOOQ. An example is given here:

    - result = create.fetch(sql); // Or execute that SQL with JDBC, fetching the ResultSet with jOOQ: ResultSet rs = connection.createStatement().executeQuery(sql); -Result result = create.fetch(rs);]]> +Result result = create.fetch(rs);]]>

    If you wish to use jOOQ as a SQL executor with (or without) code generation, the following sections of the manual will be of interest to you: @@ -552,17 +543,17 @@ Result result = create.fetch(rs);]]>

  • : This section contains a lot of information about executing SQL statements using the jOOQ API
  • : This section contains some useful information about the various ways of fetching data with jOOQ
  • -
    +
    jOOQ for CRUD - +

    This is probably the most complete use-case for jOOQ: Use all of jOOQ's features. Apart from jOOQ's fluent API for query construction, jOOQ can also help you execute everyday CRUD operations. An example is given here:

    - +}]]>

    If you wish to use all of jOOQ's features, the following sections of the manual will be of interest to you (including all sub-sections): @@ -586,12 +577,12 @@ for (AuthorRecord author : create.fetch(AUTHOR)) {

  • : This section contains the necessary information to run jOOQ's code generator against your developer database
  • : This section contains a lot of information about executing SQL statements using the jOOQ API
  • -
    +
    jOOQ for PROs - +

    jOOQ isn't just a library that helps you and SQL against your . jOOQ ships with a lot of tools. Here are some of the most important tools shipped with jOOQ:

    @@ -606,32 +597,32 @@ for (AuthorRecord author : create.fetch(AUTHOR)) {

    If you're a power user of your favourite, feature-rich database, jOOQ will help you access all of your database's vendor-specific features, such as OLAP features, stored procedures, user-defined types, vendor-specific SQL, functions, etc. Examples are given throughout this manual.

    -
    +
    Tutorials - +

    Don't have time to read the full manual? Here are a couple of tutorials that will get you into the most essential parts of jOOQ as quick as possible.

    -
    +
    jOOQ in 7 easy steps - +

    This manual section is intended for new users, to help them get a running application with jOOQ, quickly.

    -
    +
    Step 1: Preparation - +

    If you haven't already downloaded it, download jOOQ:
    https://sourceforge.net/projects/jooq/files/Release/ @@ -640,7 +631,7 @@ for (AuthorRecord author : create.fetch(AUTHOR)) {

    Alternatively, you can create a Maven dependency to download jOOQ artefacts:

    - + org.jooq jooq {jooq-version} @@ -654,7 +645,7 @@ for (AuthorRecord author : create.fetch(AUTHOR)) { org.jooq jooq-codegen {jooq-version} -]]> +]]>

    Please refer to the manual's section about to learn how to use jOOQ's code generator with Maven. @@ -668,17 +659,17 @@ for (AuthorRecord author : create.fetch(AUTHOR)) {

    If you don't have a MySQL instance up and running yet, get XAMPP now! XAMPP is a simple installation bundle for Apache, MySQL, PHP and Perl

    -
    +
    Step 2: Your database - +

    We're going to create a database called "guestbook" and a corresponding "posts" table. Connect to MySQL via your command line client and type the following:

    -CREATE DATABASE guestbook; +CREATE DATABASE guestbook; CREATE TABLE `posts` ( `id` bigint(20) NOT NULL, @@ -687,13 +678,12 @@ CREATE TABLE `posts` ( `title` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ); - -
    +
    Step 3: Code generation - +

    In this step, we're going to use jOOQ's command line tools to generate classes that map to the Posts table we just created. More detailed information about how to set up the jOOQ code generator can be found here:
    @@ -703,7 +693,7 @@ CREATE TABLE `posts` ( The easiest way to generate a schema is to copy the jOOQ jar files (there should be 3) and the MySQL Connector jar file to a temporary directory. Then, create a guestbook.xml that looks like this:

    - + @@ -746,7 +736,7 @@ CREATE TABLE `posts` ( C:/workspace/MySQLTest/src -]]> +]]>

    Replace the username with whatever user has the appropriate privileges to query the database meta data. You'll also want to look at the other values and replace as necessary. Here are the two interesting properties:

    @@ -761,15 +751,15 @@ CREATE TABLE `posts` ( Once you have the JAR files and guestbook.xml in your temp directory, type this (use colons instead of semi-colons on UNIX/Linux systems):

    -java -classpath jooq-{jooq-version}.jar;jooq-meta-{jooq-version}.jar;jooq-codegen-{jooq-version}.jar;mysql-connector-java-5.1.18-bin.jar;. +java -classpath jooq-{jooq-version}.jar;jooq-meta-{jooq-version}.jar;jooq-codegen-{jooq-version}.jar;mysql-connector-java-5.1.18-bin.jar;. org.jooq.util.GenerationTool /guestbook.xml - +

    Note the prefix slash before guestbook.xml. Even though it's in our working directory, we need to prepend a slash, as the configuration file is loaded from the classpath. Replace the filenames with your filenames. In this example, jOOQ {jooq-version} is being used. If everything has worked, you should see this in your console output:

    -Nov 1, 2011 7:25:06 PM org.jooq.impl.JooqLogger info +Nov 1, 2011 7:25:06 PM org.jooq.impl.JooqLogger info INFO: Initialising properties : /guestbook.xml Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info INFO: Database parameters @@ -825,19 +815,17 @@ Nov 1, 2011 7:25:08 PM org.jooq.impl.JooqLogger info INFO: Packages fetched : 0 (0 included, 0 excluded) Nov 1, 2011 7:25:08 PM org.jooq.impl.JooqLogger info INFO: GENERATION FINISHED! : Total: 791.688ms, +9.143ms - - -
    +
    Step 4: Connect to your database - +

    Let's just write a vanilla main class in the project containing the generated classes:

    - +}]]>

    This is pretty standard code for establishing a MySQL connection.

    -
    +
    Step 5: Querying - +

    Let's add a simple query:

    - result = create.select().from(POSTS).fetch();]]> + result = create.select().from(POSTS).fetch();]]>

    First get an instance of DSLContext so we can write a simple SELECT query. We pass an instance of the MySQL connection to DSL. Note that the DSLContext doesn't close the connection. We'll have to do that ourselves. @@ -888,29 +876,29 @@ Result result = create.select().from(POSTS).fetch();]]>

    We then use jOOQ's DSL to return an instance of Result. We'll be using this result in the next step.

    -
    +
    Step 6: Iterating - +

    After the line where we retrieve the results, let's iterate over the results and print out the data:

    - +}]]>

    The full program should now look like this:

    - -
    +}]]>
    Step 7: Explore! - +

    jOOQ has grown to be a comprehensive SQL library. For more information, please consider the documentation:
    http://www.jooq.org/learn.php @@ -983,21 +970,21 @@ public class Main { This tutorial is the courtesy of Ikai Lan. See the original source here:
    http://ikaisays.com/2011/11/01/getting-started-with-jooq-a-tutorial/

    -
    +
    Using jOOQ in modern IDEs - +

    Feel free to contribute a tutorial!

    -
    +
    Using jOOQ with Spring and DBCP - +

    jOOQ and Spring are easy to integrate. In this example, we shall integrate:

    @@ -1016,7 +1003,7 @@ public class Main { For this example, we'll create the following Maven dependencies

    - + 3.2.3.RELEASE @@ -1058,14 +1045,14 @@ public class Main { ${org.springframework.version} -]]> +]]>

    Create a minimal Spring configuration file

    The above dependencies are configured together using a Spring Beans configuration:

    - + @@ -1108,14 +1095,14 @@ public class Main { -]]> +]]>

    Run a query in the JDBC Connection's transaction:

    The following simple program shows how you can now easily obtain a instance, from which queries can be executed:

    - +}]]>

    The above example shows how Spring's TransactionAwareDataSourceProxy discovers that a jOOQ query is not executed in a transactional context. @@ -1149,7 +1136,7 @@ public class Test { The following simple program shows how Spring's TransactionAwareDataSourceProxy will discover that several jOOQ queries are executed in the context of an explicitly created transaction

    - +}]]>

    Of course, in an actual productive setup, you are more likely to use Spring's AOP features to declare transactions and transactional behaviour on service methods, instead of explicitly starting and committing / rollbacking transactions. There are many other transaction models that you can choose to use with jOOQ.

    -
    +
    A simple web application with jOOQ - +

    Feel free to contribute a tutorial!

    -
    +
    jOOQ and Scala - +

    As any other library, jOOQ can be easily used in Scala, taking advantage of the many Scala language features such as for example:

    @@ -1221,7 +1208,7 @@ public class Test { A short example jOOQ application in Scala might look like this:

    - +}]]>

    For more details about jOOQ's Scala integration, please refer to the manual's section about .

    -
    +
    Dependencies - +

    Dependencies are a big hassle in modern software. Many libraries depend on other, non-JDK library parts that come in different, incompatible versions, potentially causing trouble in your runtime environment. jOOQ has no external dependencies on any third-party libraries.

    @@ -1282,12 +1269,12 @@ object Test { //
  • Small libraries with compatible licenses are incorporated into jOOQ. These include jOOR, jOOU, parts of OpenCSV, json simple, parts of commons-lang
  • javax.persistence and javax.validation will be needed if you activate the relevant
  • -
    +
    Build your own - +

    In order to build jOOQ yourself, please download the sources from https://github.com/jOOQ/jOOQ and use Maven to build jOOQ, preferably in Eclipse. jOOQ requires Java 6+ to compile and run.

    @@ -1311,12 +1298,12 @@ object Test { // -
    +
    jOOQ and backwards-compatibility - +

    jOOQ follows the rules of semantic versioning according to http://semver.org quite strictly. Those rules impose a versioning scheme [X].[Y].[Z] that can be summarised as follows:

    @@ -1344,14 +1331,14 @@ object Test { //

    jOOQ's DSL interfaces should not be implemented by client code! Extend only those extension points that are explicitly documented as "extendable" (e.g. )

    -
    +
    SQL building - +

    SQL is a declarative language that is hard to integrate into procedural, object-oriented, functional or any other type of programming languages. jOOQ's philosophy is to give SQL the credit it deserves and integrate SQL itself as an "internal domain specific language" directly into Java.

    @@ -1361,7 +1348,7 @@ object Test { //

    This section explains all about the various syntax elements involved with jOOQ's SQL building capabilities. For a complete overview of all syntax elements, please refer to the manual's sections about as well as

    -
    +
    @@ -1370,7 +1357,7 @@ object Test { //
    The DSL type - +

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

    @@ -1388,21 +1375,20 @@ object Test { // With jOOQ 2.0, static factory methods have been introduced in order to make client code look more like SQL. Ideally, when working with jOOQ, you will simply static import all methods from the DSL class:

    -import static org.jooq.impl.DSL.*; +import static org.jooq.impl.DSL.*;

    Note, that when working with Eclipse, you could also add the DSL to your favourites. This will allow to access functions even more fluently:

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

    There are a couple of subclasses for the general DSL. Each SQL dialect has its own dialect-specific DSL. For instance, if you're only using the MySQL dialect, you can choose to reference the MySQLDSL instead of the standard DSL:

    @@ -1413,7 +1399,7 @@ DSL.concat(DSL.trim(FIRST_NAME), DSL.trim(LAST_NAME));
  • MySQL's encryption functions
  • PL/SQL constructs, pgplsql, or any other dialect's ROUTINE-language (maybe in the future)
  • -
    +
    @@ -1429,7 +1415,7 @@ DSL.concat(DSL.trim(FIRST_NAME), DSL.trim(LAST_NAME));
    The DSLContext class - +

    DSLContext references a , an object that configures jOOQ's behaviour when executing queries (see for more details). Unlike the static DSL, the DSLContext allow for creating that are already "configured" and ready for execution.

    @@ -1439,11 +1425,11 @@ DSL.concat(DSL.trim(FIRST_NAME), DSL.trim(LAST_NAME)); The DSLContext object can be created fluently from the :

    - +DSLContext create = DSL.using(connection, dialect);]]>

    If you do not have a reference to a pre-existing Configuration object (e.g. created from ), the various overloaded DSL.using() methods will create one for you. @@ -1471,32 +1457,31 @@ DSLContext create = DSL.using(connection, dialect);]]>

    Wrapping a Configuration object, a DSLContext can construct , for later . An example is given here:

    - select = create.selectOne(); // Using the internally referenced Configuration, the select statement can now be executed: -Result result = select.fetch();]]> +Result result = select.fetch();]]>

    Note that you do not need to keep a reference to a DSLContext. You may as well inline your local variable, and fluently execute a SQL statement as such:

    - result = DSL.using(connection, dialect) .select() .from(BOOK) .where(BOOK.TITLE.like("Animal%")) - .fetch();]]> -
    + .fetch();]]>
    SQL Dialect - +

    While jOOQ tries to represent the SQL standard as much as possible, many features are vendor-specific to a given database and to its "SQL dialect". jOOQ models this using the enum type.

    @@ -1506,27 +1491,27 @@ DSL.using(connection, dialect)

    Some parts of the jOOQ API are officially supported only by a given subset of the supported SQL dialects. For instance, the , which is supported by the Oracle and CUBRID databases, is annotated with a annotation, as such:

    -CONNECT BY clause to the query */ @Support({ SQLDialect.CUBRID, SQLDialect.ORACLE }) -SelectConnectByConditionStep connectBy(Condition condition);]]> +SelectConnectByConditionStep connectBy(Condition condition);]]>

    jOOQ API methods which are not annotated with the annotation, or which are annotated with the Support annotation, but without any SQL dialects can be safely used in all SQL dialects. An example for this is the factory method:

    - select(Field... fields);]]> +SelectSelectStep select(Field... fields);]]>

    jOOQ's SQL clause simulation capabilities

    The aforementioned Support annotation does not only designate, which databases natively support a feature. It also indicates that a feature is simulated by jOOQ for some databases lacking this feature. An example of this is the , a predicate syntax defined by SQL:1999 and implemented only by H2, HSQLDB, and Postgres:

    - +

    Nevertheless, the IS DISTINCT FROM predicate is supported by jOOQ in all dialects, as its semantics can be expressed with an equivalent . For more details, see the manual's section about the . @@ -1546,12 +1531,12 @@ SelectSelectStep select(Field... fields);]]>

    jOOQ has a historic affinity to Oracle's SQL extensions. If something is supported in Oracle SQL, it has a high probability of making it into the jOOQ API

    -
    +
    SQL Dialect Family - +

    In jOOQ 3.1, the notion of a SQLDialect.family() was introduced, in order to group several similar into a common family. An example for this is SQL Server, which is supported by jOOQ in various versions:

    @@ -1565,12 +1550,12 @@ SelectSelectStep select(Field... fields);]]>

    In the above list, SQLSERVER is both a dialect and a family of three dialects. This distinction is used internally by jOOQ to distinguish whether to use the clause (SQL Server 2012), or whether to simulate it using ROW_NUMBER() OVER() (SQL Server 2008).

    -
    +
    Connection vs. DataSource - +

    Interact with JDBC Connections

    While you can use jOOQ for only, you can also run queries against a JDBC . Internally, jOOQ creates or objects from such a Connection, in order to execute statements. The normal operation mode is to provide a with a JDBC Connection, whose lifecycle you will control yourself. This means that jOOQ will not actively close connections, rollback or commit transactions. @@ -1592,24 +1577,24 @@ SelectSelectStep select(Field... fields);]]> If your specific environment works differently from any of the above approaches, you can inject your own custom implementation of a ConnectionProvider into jOOQ. This is the API contract you have to fulfil:

    - +}]]>

    Note that acquire() should always return the same Connection until this connection is returned via release()

    -
    +
    Custom data - +

    In advanced use cases of integrating your application with jOOQ, you may want to put custom data into your , which you can then access from your...

    @@ -1623,7 +1608,7 @@ SelectSelectStep select(Field... fields);]]> Here is an example of how to use the custom data API. Let's assume that you have written an , that prevents INSERT statements, when a given flag is set to true:

    - +}]]>

    See the manual's section about to learn more about how to implement an ExecuteListener.

    @@ -1647,7 +1632,7 @@ public class NoInsertListener extends DefaultExecuteListener { Now, the above listener can be added to your , but you will also need to pass the flag to the Configuration, in order for the listener to work:

    - +}]]>

    Using the data() methods, you can store and retrieve custom data in your Configurations.

    -
    +
    Custom ExecuteListeners - +

    ExecuteListeners are a useful tool to...

    @@ -1696,7 +1681,7 @@ catch (DataAccessException expected) { ExecuteListeners are hooked into your by returning them from an :

    - +);]]>

    See the manual's section about to see examples of such listener implementations.

    -
    +
    Custom Settings - +

    The jOOQ Configuration 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 Configuration in several ways:

    @@ -1729,9 +1714,9 @@ configuration.set(

    For example, if you want to indicate to jOOQ, that it should inline all bind variables, and execute static instead of binding its variables to , you can do so by creating the following DSLContext:

    - +DSLContext create = DSL.using(connection, dialect, settings);]]>

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

    @@ -1750,12 +1735,12 @@ DSLContext create = DSL.using(connection, dialect, settings);]]> Please refer to the jOOQ runtime configuration XSD for more details:
    http://www.jooq.org/xsd/jooq-runtime-{runtime-xsd-version}.xsd

    -
    +
    Runtime schema and table mapping - +

    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. @@ -1775,7 +1760,7 @@ DSLContext create = DSL.using(connection, dialect, settings);]]> 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 Configuration's with. Take the following example:

    -Settings settings = new Settings() +Settings settings = new Settings() .withRenderMapping(new RenderMapping() .withSchemata( new MappedSchema().withInput("DEV") @@ -1785,13 +1770,13 @@ DSLContext create = DSL.using(connection, dialect, settings);]]> DSLContext create = DSL.using(connection, SQLDialect.ORACLE, settings); // Run queries with the "mapped" Configuration -create.selectFrom(AUTHOR).fetch(); +create.selectFrom(AUTHOR).fetch();

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

    -SELECT * FROM MY_BOOK_WORLD.AUTHOR +SELECT * FROM MY_BOOK_WORLD.AUTHOR

    Even if AUTHOR was generated from DEV.

    @@ -1801,7 +1786,7 @@ create.selectFrom(AUTHOR).fetch(); 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):

    - + @@ -1814,13 +1799,13 @@ create.selectFrom(AUTHOR).fetch(); -]]> +]]>

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

    -Settings settings = JAXB.unmarshal(new File("jooq-runtime.xml"), Settings.class); +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 Configuration. @@ -1833,21 +1818,21 @@ create.selectFrom(AUTHOR).fetch();

    -Settings settings = new Settings() +Settings settings = new Settings() .withRenderSchema(false); // Add the settings to the Configuration DSLContext create = DSL.using(connection, SQLDialect.ORACLE, settings); // Run queries that omit rendering schema names -create.selectFrom(AUTHOR).fetch(); +create.selectFrom(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.AUTHOR to something MY_BOOK_WORLD.MY_APP__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() +Settings settings = new Settings() .withRenderMapping(new RenderMapping() .withSchemata( new MappedSchema().withInput("DEV") @@ -1860,13 +1845,13 @@ create.selectFrom(AUTHOR).fetch(); DSLContext create = DSL.using(connection, SQLDialect.ORACLE, settings); // Run queries with the "mapped" configuration -create.selectFrom(AUTHOR).fetch(); +create.selectFrom(AUTHOR).fetch();

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

    -SELECT * FROM MY_BOOK_WORLD.MY_APP__AUTHOR +SELECT * FROM MY_BOOK_WORLD.MY_APP__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! @@ -1876,23 +1861,23 @@ create.selectFrom(AUTHOR).fetch();

    Note that the manual's section about explains how you can hard-wire your schema mappings at code generation time

    -
    +
    SQL Statements - +

    jOOQ currently supports 6 types of SQL statements. All of these statements are constructed from a DSLContext instance with an optional . If supplied with a Connection or DataSource, they can be executed. Depending on the , executed queries can return results.

    -
    +
    jOOQ's DSL and model API - +

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

    @@ -1900,22 +1885,21 @@ create.selectFrom(AUTHOR).fetch(); Here is an example to illustrate what that means:

    - 1920 AND a.first_name = 'Paulo' - ORDER BY b.title]]> - result = + ORDER BY b.title]]> result = create.select() .from(AUTHOR.as("a")) .join(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();]]> + .fetch();]]>

    We'll see how the aliasing works later in the section about @@ -1926,16 +1910,16 @@ create.select() Many other frameworks have similar APIs with similar feature sets. Yet, what makes jOOQ special is its informal modelling a unified SQL dialect suitable for many vendor-specific dialects, and implementing that BNF notation as a hierarchy of interfaces in Java. This concept is extremely powerful, when with syntax completion. Not only can you code much faster, your SQL code will be compile-checked to a certain extent. An example of a DSL query equivalent to the previous one is given here:

    - result = create.select() .from(AUTHOR) .join(BOOK).on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)) - .fetch();]]> + .fetch();]]>

    Unlike other, simpler frameworks that use "fluent APIs" or "method chaining", jOOQ's BNF-based interface hierarchy will not allow bad query syntax. The following will not compile, for instance:

    - result = create.select() .join(BOOK).on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)) // ^^^^ "join" is not possible here @@ -1965,14 +1949,14 @@ Result result = create.select() .where(AUTHOR.ID.in(select(BOOK.AUTHOR_ID, BOOK.ID).from(BOOK))) // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // AUTHOR.ID is of degree 1 but subselect returns Record2 - .fetch();]]> + .fetch();]]>

    History of SQL building and incremental query building (a.k.a. the model API)

    Historically, jOOQ started out as an object-oriented SQL builder library like any other. This meant that all queries and their syntactic components were modeled as so-called , which delegate and to child components. This part of the API will be referred to as the model API (or non-DSL API), which is still maintained and used internally by jOOQ for incremental query building. An example of incremental query building is given here:

    - query = create.selectQuery(); query.addFrom(AUTHOR); @@ -1981,25 +1965,25 @@ if (join) { query.addJoin(BOOK, BOOK.AUTHOR_ID.equal(AUTHOR.ID)); } -Result result = query.fetch();]]> +Result result = query.fetch();]]>

    This query is equivalent to the one shown before using the DSL syntax. In fact, internally, the DSL API constructs precisely this SelectQuery object. Note, that you can always access the SelectQuery object to switch between DSL and model APIs:

    - select = create.select().from(AUTHOR); // Add the JOIN clause on the internal QueryObject representation SelectQuery query = select.getQuery(); -query.addJoin(BOOK, BOOK.AUTHOR_ID.equal(AUTHOR.ID));]]> +query.addJoin(BOOK, BOOK.AUTHOR_ID.equal(AUTHOR.ID));]]>

    Mutability

    Note, that for historic reasons, the DSL API mixes mutable and immutable behaviour with respect to the internal representation of the being constructed. While creating , (such as functions) assumes immutable behaviour, creating does not. In other words, the following can be said:

    - s3 = s1.from(AUTHOR); // The following can be said s1 == s2; // The internal object is always the same -s2 == s3; // The internal object is always the same]]> +s2 == s3; // The internal object is always the same]]>

    On the other hand, beware that you can always extract and modify from any QueryPart.

    -
    +
    The SELECT statement - +

    When you don't just perform (i.e. SELECT * FROM your_table WHERE ID = ?), you're usually generating new record 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:

    SELECT from a complex table expression

    - + - - +

    Details about the various clauses of this query will be provided in subsequent sections. @@ -2080,14 +2063,14 @@ create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, count()) A very similar, but limited API is available, if you want to select from single physical tables in order to retrieve . The decision, which type of select to create is already made at the very first step, when you create the SELECT statement with the DSL or DSLContext types:

    - SelectWhereStep selectFrom(Table table);]]> + SelectWhereStep selectFrom(Table 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:

    - + .fetchAny();]]>

    The "reduced" SELECT API is limited in the way that it skips DSL access to any of these clauses: @@ -2099,41 +2082,39 @@ create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, count())

    In most parts of this manual, it is assumed that you do not use the "reduced" SELECT API. For more information about the simple SELECT API, see the manual's section about .

    -
    +
    The SELECT clause - +

    The SELECT clause lets you project your own record types, referencing table fields, functions, arithmetic expressions, etc. The DSL type provides several methods for expressing a SELECT clause:

    - + - s1 = create.select(BOOK.ID, BOOK.TITLE); Select s2 = create.select(BOOK.ID, trim(BOOK.TITLE));]]> - +

    Some commonly used projections can be easily created using convenience methods:

    - + - select1 = create.selectCount(); Select select2 = create.selectZero(); Select select2 = create.selectOne();]]> - +

    See more details about functions and expressions in the manual's section about @@ -2144,17 +2125,16 @@ Select select2 = create.selectOne();]]> The DISTINCT keyword can be included in the method name, constructing a SELECT clause

    - - - select1 = create.selectDistinct(BOOK.TITLE);]]> - + + select1 = create.selectDistinct(BOOK.TITLE);]]> +

    SELECT *

    jOOQ does not explicitly support the asterisk operator in projections. However, you can omit the projection as in these examples:

    - +create.select().from(tableByName("BOOK"));]]>

    Typesafe projections with degree up to {max-row-degree}

    Since jOOQ 3.0, and up to degree {max-row-degree} are now generically typesafe. This is reflected by an overloaded SELECT (and SELECT DISTINCT) API in both DSL and DSLContext. An extract from the DSL type:

    - select(Collection> fields); public static SelectSelectStep select(Field... fields); @@ -2177,36 +2157,35 @@ public static SelectSelectStep select(Field... fields); public static SelectSelectStep> select(Field field1); public static SelectSelectStep> select(Field field1, Field field2); public static SelectSelectStep> select(Field field1, Field field2, Field field3); -// [...]]]> +// [...]]]>

    Since the generic R type is bound to some , the associated T type information can be used in various other contexts, e.g. the . Such a SELECT statement can be assigned typesafely:

    -> s1 = create.select(BOOK.ID, BOOK.TITLE); -Select> s2 = create.select(BOOK.ID, trim(BOOK.TITLE));]]> +> s1 = create.select(BOOK.ID, BOOK.TITLE); +Select> s2 = create.select(BOOK.ID, trim(BOOK.TITLE));]]>

    For more information about typesafe record types with degree up to {max-row-degree}, see the manual's section about .

    -
    +
    The FROM clause - +

    The SQL FROM clause allows for specifying any number of to select data from. The following are examples of how to form normal FROM clauses:

    - + - - +

    Read more about aliasing in the manual's section about . @@ -2217,12 +2196,11 @@ create.selectOne().from(BOOK.as("b"), AUTHOR.as("a"));]]> Apart from simple tables, you can pass any arbitrary to the jOOQ FROM clause. This may include in Oracle:

    - + - - +

    Note, in order to access the DbmsXplan package, you can use the to generate Oracle's SYS schema. @@ -2234,22 +2212,21 @@ FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(null, null, 'ALLSTATS'));]]> In many SQL dialects, FROM is a mandatory clause, in some it isn't. jOOQ allows you to omit the FROM clause, returning just one record. An example:

    - + - - +

    Read more about dual or dummy tables in the manual's section about . The following are examples of how to form normal FROM clauses:

    -
    +
    The JOIN clause - +

    jOOQ supports many different types of standard SQL JOIN operations:

    @@ -2268,7 +2245,7 @@ DSL.using(SQLDialect.POSTGRES).selectOne().getSQL();]]> All of these JOIN methods can be called on types, or directly after the FROM clause for convenience. The following example joins AUTHOR and BOOK

    - result = create.select() @@ -2281,27 +2258,26 @@ Result result = create.select() .from(AUTHOR) .join(BOOK) .on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)) - .fetch();]]> + .fetch();]]>

    The two syntaxes will produce the same SQL statement. However, calling "join" on objects allows for more powerful, nested JOIN expressions (if you can handle the parentheses):

    - + - + .on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)));]]>
    • See the section about to learn more about the many ways to create objects in jOOQ.
    • @@ -2313,13 +2289,12 @@ create.select() Surprisingly, the SQL standard does not allow to formally JOIN on well-known foreign key relationship information. Naturally, when you join BOOK to AUTHOR, you will want to do that based on the BOOK.AUTHOR_ID foreign key to AUTHOR.ID primary key relation. Not being able to do this in SQL leads to a lot of repetitive code, re-writing the same JOIN predicate again and again - especially, when your foreign keys contain more than one column. With jOOQ, when you use , you can use foreign key constraint information in JOIN expressions as such:

      - + - + .join(BOOK).onKey();]]>

      In case of ambiguity, you can also supply field references for your foreign keys, or the generated foreign key reference to the onKey() method. @@ -2333,137 +2308,130 @@ JOIN BOOK ON BOOK.AUTHOR_ID = AUTHOR.ID]]> Most often, you will provide jOOQ with JOIN conditions in the JOIN .. ON clause. SQL supports a different means of specifying how two tables are to be joined. This is the JOIN .. USING clause. Instead of a condition, you supply a set of fields whose names are common to both tables to the left and right of a JOIN operation. This can be useful when your database schema has a high degree of relational normalisation. An example:

      - + - + .join(BOOK).using(AUTHOR.AUTHOR_ID);]]>

      In schemas with high degrees of normalisation, you may also choose to use NATURAL JOIN, which takes no JOIN arguments as it joins using all fields that are common to the table expressions to the left and to the right of the JOIN operator. An example:

      - + - + .naturalJoin(BOOK);]]>

      Oracle's partitioned OUTER JOIN

      Oracle SQL ships with a special syntax available for OUTER JOIN clauses. According to the Oracle documentation about partitioned outer joins this can be used to fill gaps for simplified analytical calculations. jOOQ only supports putting the PARTITION BY clause to the right of the OUTER JOIN clause. The following example will create at least one record per AUTHOR and per existing value in BOOK.PUBLISHED_IN, regardless if an AUTHOR has actually published a book in that year.

      - + - + .on(BOOK.AUTHOR_ID.equal(AUTHOR.ID));]]> - +
    The WHERE clause - +

    The WHERE clause can be used for JOIN or filter predicates, in order to restrict the data returned by the supplied to the previously specified and . Here is an example:

    - + - + .and(BOOK.TITLE.equal("1984"));]]>

    The above syntax is convenience provided by jOOQ, allowing you to connect the supplied in the WHERE clause with another condition using an AND operator. You can of course also create a more complex condition and supply that to the WHERE clause directly (observe the different placing of parentheses). The results will be the same:

    - + - + BOOK.TITLE.equal("1984")));]]>

    You will find more information about creating later in the manual.

    -
    +
    The CONNECT BY clause - +

    The Oracle database knows a very succinct syntax for creating hierarchical queries: the CONNECT BY clause, which is fully supported by jOOQ, including all related functions and pseudo-columns. A more or less formal definition of this clause is given here:

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

    An example for an iterative query, iterating through values between 1 and 5 is this:

    - + - + .connectBy(level().lessOrEqual(5));]]>

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

    - + - - +

    The output might then look like this

    -+------------------------------------------------+ ++------------------------------------------------+ |substring | +------------------------------------------------+ |C: | @@ -2473,7 +2441,7 @@ ORDER BY 1]]> |C:/eclipse/eclipse.exe | +------------------------------------------------+ |...21 record(s) truncated... - +

    Some of the supported functions and pseudo-columns are these (available from the ): @@ -2497,38 +2465,36 @@ ORDER BY 1]]> The Oracle database allows for specifying a SIBLINGS keyword in the . Instead of ordering the overall result, this will only order siblings among each other, keeping the hierarchy intact. An example is given here:

    - + - - + -
    +
    The GROUP BY clause - +

    GROUP BY can be used to create unique groups of data, to form aggregations, to remove duplicates and for other reasons. It will transform your previously defined , and return only one record per unique group as specified in this clause. For instance, you can group books by BOOK.AUTHOR_ID:

    - + - + .groupBy(BOOK.AUTHOR_ID);]]>

    The above example counts all books per author. @@ -2542,13 +2508,12 @@ GROUP BY AUTHOR_ID]]> MySQL has a peculiar way of not adhering to this standard behaviour. This is documented in the MySQL manual. In short, with MySQL, you can also project any other field that is not part of the GROUP BY clause. The projected values will just be arbitrary values from within the group. You cannot rely on any ordering. For example:

    - + - + .groupBy(AUTHOR_ID);]]>

    This will return an arbitrary title per author. jOOQ supports this syntax, as jOOQ is not doing any checks internally, about the consistence of tables/fields/functions that you provide it. @@ -2559,68 +2524,64 @@ GROUP BY AUTHOR_ID]]> jOOQ supports empty GROUP BY () clause as well. This will result in that return only one record.

    - + - + .groupBy();]]>

    ROLLUP(), CUBE() and GROUPING SETS()

    Some databases support the SQL standard grouping functions and some extensions thereof. See the manual's section about for more details.

    -
    +
    The HAVING clause - +

    The HAVING clause is commonly used to further restrict data resulting from a previously issued . An example, selecting only those authors that have written at least two books:

    - + = 2]]> -= 2]]> + .having(count().greaterOrEqual(2));]]>

    According to the SQL standard, you may omit the GROUP BY clause and still issue a HAVING clause. This will implicitly GROUP BY (). jOOQ also supports this syntax. The following example selects one record, only if there are at least 4 books in the books table:

    - + = 4]]> -= 4]]> + .having(count().greaterOrEqual(4));]]> -
    +
    The ORDER BY clause - +

    Databases are allowed to return data in any arbitrary order, unless you explicitly declare that order in the ORDER BY clause. In jOOQ, this is straight-forward:

    - + - + .orderBy(BOOK.AUTHOR_ID.asc(), BOOK.TITLE.desc());]]>

    Any jOOQ can be transformed into an by calling the asc() and desc() methods. @@ -2631,13 +2592,12 @@ ORDER BY AUTHOR_ID ASC, TITLE DESC]]> The SQL standard allows for specifying integer literals (, not !) to reference column indexes from the projection (). This may be useful if you do not want to repeat a lengthy expression, by which you want to order - although most databases also allow for referencing in the ORDER BY clause. An example of this is given here:

    - + - + .orderBy(one().asc(), inline(2).desc());]]>

    Note, how one() is used as a convenience short-cut for inline(1) @@ -2648,87 +2608,84 @@ ORDER BY 1 ASC, 2 DESC]]> A few databases support the SQL standard "null ordering" clause in sort specification lists, to define whether NULL values should come first or last in an ordered result.

    - + - + BOOK.CO_AUTHOR_ID.asc().nullsLast());]]>

    If your database doesn't support this syntax, jOOQ simulates it using a as follows

    - + - + BOOK.CO_AUTHOR_ID.asc().nullsLast());]]>

    Ordering using CASE expressions

    Using in SQL ORDER BY clauses is a common pattern, if you want to introduce some sort indirection / sort mapping into your queries. As with SQL, you can add any type of into your ORDER BY clause. For instance, if you have two favourite books that you always want to appear on top, you could write:

    - + - + .otherwise(2).asc());]]>

    But writing these things can become quite verbose. jOOQ supports a convenient syntax for specifying sort mappings. The same query can be written in jOOQ as such:

    - + .orderBy(BOOK.TITLE.sortAsc("1984", "Animal Farm"));]]>

    More complex sort indirections can be provided using a Map:

    -() {{ put("1984", 1); put("Animal Farm", 13); put("The jOOQ book", 10); - }}));]]> + }}));]]>

    Of course, you can combine this feature with the previously discussed NULLS FIRST / NULLS LAST feature. So, if in fact these two books are the ones you like least, you can put all NULLS FIRST (all the other books):

    - + .orderBy(BOOK.TITLE.sortAsc("1984", "Animal Farm").nullsFirst());]]>

    jOOQ's understanding of SELECT .. ORDER BY

    @@ -2740,23 +2697,23 @@ ORDER BY CASE TITLE

    jOOQ also supports Oracle's SIBLINGS keyword to be used with ORDER BY clauses for

    -
    +
    The LIMIT .. OFFSET clause - +

    While being extremely useful for every application that does paging, or just to limit result sets to reasonable sizes, this clause is not yet part of any SQL standard (up until SQL:2008). Hence, there exist a variety of possible implementations in various SQL dialects, concerning this limit clause. jOOQ chose to implement the LIMIT .. OFFSET clause as understood and supported by MySQL, H2, HSQLDB, Postgres, and SQLite. Here is an example of how to apply limits with jOOQ:

    - +

    This will limit the result to 1 books starting with the 2nd book (starting at offset 0!). limit() is supported in all dialects, offset() in all but Sybase ASE, which has no reasonable means to simulate it. This is how jOOQ simulates the above query in various SQL dialects:

    - 1 AND ROWNUM_98843777 <= 3 -]]> +]]>

    As you can see, jOOQ will take care of the incredibly painful ROW_NUMBER() OVER() (or ROWNUM for Oracle) filtering in subselects for you, you'll just have to write limit(1).offset(2) in any dialect. @@ -2801,39 +2758,37 @@ AND ROWNUM_98843777 <= 3

    As can be seen in the above example, writing correct SQL can be quite tricky, depending on the SQL dialect. For instance, with SQL Server, you cannot have an ORDER BY clause in a subquery, unless you also have a TOP clause. This is illustrated by the fact that jOOQ renders a TOP 100 PERCENT clause for you. The same applies to the fact that ROW_NUMBER() OVER() needs an ORDER BY windowing clause, even if you don't provide one to the jOOQ query. By default, jOOQ adds ordering by the first column of your projection.

    -
    +
    The FOR UPDATE clause - +

    For inter-process synchronisation and other reasons, you may choose to use the SELECT .. FOR UPDATE clause to indicate to the database, that a set of cells or records should be locked by a given transaction for subsequent updates. With jOOQ, this can be achieved as such:

    - + - + .forUpdate();]]>

    The above example will produce a record-lock, locking the whole record for updates. Some databases also support cell-locks using FOR UPDATE OF ..

    - + - + .forUpdate().of(BOOK.TITLE);]]>

    Oracle goes a bit further and also allows to specify the actual locking behaviour. It features these additional clauses, which are all supported by jOOQ: @@ -2847,15 +2802,15 @@ FOR UPDATE OF TITLE]]> With jOOQ, you can use those Oracle extensions as such:

    - +create.select().from(BOOK).where(BOOK.ID.equal(3)).forUpdate().skipLocked();]]>

    FOR UPDATE in CUBRID and SQL Server

    The SQL standard specifies a FOR UPDATE clause to be applicable for cursors. Most databases interpret this as being applicable for all SELECT statements. An exception to this rule are the CUBRID and SQL Server databases, that do not allow for any FOR UPDATE clause in a regular SQL SELECT statement. jOOQ simulates the FOR UPDATE behaviour, by locking record by record with JDBC. JDBC allows for specifying the flags TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE for any statement, and then using ResultSet.updateXXX() methods to produce a cell-lock / row-lock. Here's a simplified example in JDBC:

    - +}]]>

    The main drawback of this approach is the fact that the database has to maintain a scrollable cursor, whose records are locked one by one. This can cause a major risk of deadlocks or race conditions if the JDBC driver can recover from the unsuccessful locking, if two Java threads execute the following statements:

    - +SELECT * FROM author ORDER BY id DESC;]]>

    So use this technique with care, possibly only ever locking single rows! @@ -2892,12 +2847,12 @@ SELECT * FROM author ORDER BY id DESC;]]>

    Note, that jOOQ also supports optimistic locking, if you're doing simple CRUD. This is documented in the section's manual about .

    -
    +
    UNION, INTERSECTION and EXCEPT - +

    SQL allows to perform set operations as understood in standard set theory on result sets. These operations include unions, intersections, subtractions. For two subselects to be combinable by such a set operator, each subselect must return a of the same degree and type.

    @@ -2907,13 +2862,12 @@ SELECT * FROM author ORDER BY id DESC;]]> These operators combine two results into one. While UNION removes all duplicate records resulting from this combination, UNION ALL leaves subselect results as they are. Typically, you should prefer UNION ALL over UNION, if you don't really need to remove duplicates. The following example shows how to use such a UNION operation in jOOQ.

    - + - +create.selectFrom(BOOK).where(BOOK.ID.equal(5)));]]>

    INTERSECT [ ALL ] and EXCEPT [ ALL ]

    @@ -2925,24 +2879,23 @@ create.selectFrom(BOOK).where(BOOK.ID.equal(5)));]]> As previously mentioned in the manual's section about the , jOOQ has slightly changed the semantics of these set operators. While in SQL, a subselect may not contain any or (unless you wrap the subselect into a ), jOOQ allows you to do so. In order to select both the youngest and the oldest author from the database, you can issue the following statement with jOOQ (rendered to the MySQL dialect):

    - + - + .orderBy(AUTHOR.DATE_OF_BIRTH.desc()).limit(1));]]>

    Projection typesafety for degrees between 1 and {max-row-degree}

    Two subselects that are combined by a set operator are required to be of the same degree and, in most databases, also of the same type. jOOQ 3.0's introduction of helps compile-checking these constraints:

    -> s1 = select(BOOK.ID, BOOK.TITLE).from(BOOK); Select> s2 = selectOne(); Select> s3 = select(one(), zero()); @@ -2951,46 +2904,44 @@ Select> s4 = select(one(), inline("abc")); // Let's try to combine them: s1.union(s2); // Doesn't compile because of a degree mismatch. Expected: Record2<...>, got: Record1<...> s1.union(s3); // Doesn't compile because of a type mismatch. Expected: , got: -s1.union(s4); // OK. The two Record[N] types match]]> -
    +s1.union(s4); // OK. The two Record[N] types match]]>
    Oracle-style hints - +

    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 AUTHOR +SELECT /*+ALL_ROWS*/ FIRST_NAME, LAST_NAME + FROM AUTHOR

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

    -create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) +create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .hint("/*+ALL_ROWS*/") - .from(AUTHOR); + .from(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. This can be useful in other databases too, such as MySQL, for instance:

    - + - - -
    + +
    Lexical and logical SELECT clause order - +

    SQL has a lexical and a logical order of SELECT clauses. The lexical order of SELECT clauses is inspired by the English language. As SQL statements are commands for the database, it is natural to express a statement in an imperative tense, such as "SELECT this and that!".

    @@ -3043,7 +2994,7 @@ FROM table1

    A LINQ example:

    - +Select p]]>

    A SLICK example:

    - +} yield (c.name, c.price)]]>

    While this looks like a good idea at first, it only complicates translation to more advanced SQL statements while impairing readability for those users that are used to writing SQL. jOOQ is designed to look just like SQL. This is specifically true for SLICK, which not only changed the SELECT clause order, but also heavily "integrated" SQL clauses with the Scala language. @@ -3072,48 +3023,46 @@ val q = for {

    For these reasons, the jOOQ DSL API is modelled in SQL's lexical order.

    -
    +
    The INSERT statement - +

    The INSERT statement is used to insert new records into a database table. Records can either be supplied using a VALUES() constructor, or a SELECT statement. jOOQ supports both types of INSERT statements. An example of an INSERT statement using a VALUES() constructor is given here:

    - + INSERT INTO AUTHOR (ID, FIRST_NAME, LAST_NAME) -VALUES (100, 'Hermann', 'Hesse'); -create.insertInto(AUTHOR, +VALUES (100, 'Hermann', 'Hesse');create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) - .values(100, "Hermann", "Hesse"); + .values(100, "Hermann", "Hesse");

    Note that for explicit degrees up to {max-row-degree}, the VALUES() constructor provides additional typesafety. The following example illustrates this:

    - step = + step = create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME); step.values("A", "B", "C"); - // ^^^ Doesn't compile, the expected type is Integer]]> + // ^^^ Doesn't compile, the expected type is Integer]]>

    INSERT multiple rows with the VALUES() constructor

    The SQL standard specifies that multiple rows can be supplied to the VALUES() constructor in an INSERT statement. Here's an example of a multi-record INSERT

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

    jOOQ tries to stay close to actual SQL. In detail, however, Java's expressiveness is limited. That's why the values() clause is repeated for every record in multi-record inserts. @@ -3122,30 +3071,29 @@ VALUES (100, 'Hermann', 'Hesse'), Some RDBMS do not support inserting several records in a single statement. In those cases, jOOQ simulates multi-record INSERTs using the following SQL:

    - + INSERT INTO AUTHOR (ID, FIRST_NAME, LAST_NAME) SELECT 100, 'Hermann', 'Hesse' FROM DUAL UNION ALL -SELECT 101, 'Alfred', 'Döblin' FROM DUAL; -create.insertInto(AUTHOR, +SELECT 101, 'Alfred', 'Döblin' FROM DUAL;create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .values(100, "Hermann", "Hesse") .values(101, "Alfred", "Döblin"); - +

    INSERT using jOOQ's alternative syntax

    MySQL (and some other RDBMS) allow for using a non-SQL-standard, 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(AUTHOR) +create.insertInto(AUTHOR) .set(AUTHOR.ID, 100) .set(AUTHOR.FIRST_NAME, "Hermann") .set(AUTHOR.LAST_NAME, "Hesse") .newRecord() .set(AUTHOR.ID, 101) .set(AUTHOR.FIRST_NAME, "Alfred") - .set(AUTHOR.LAST_NAME, "Döblin"); + .set(AUTHOR.LAST_NAME, "Döblin");

    As you can see, this syntax is a bit more verbose, but also more readable, as every field can be matched with its value. Internally, the two syntaxes are strictly equivalent. @@ -3156,12 +3104,12 @@ SELECT 101, 'Alfred', 'Döblin' FROM DUAL; 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 (i.e. if they support the SQL standard ). Here is an example how to use the ON DUPLICATE KEY UPDATE clause:

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

    The synthetic ON DUPLICATE KEY IGNORE clause

    @@ -3169,18 +3117,18 @@ create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.LAST_NAME) 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 :

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

    Postgres's INSERT .. RETURNING

    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:

    - record = create.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .values("Charlotte", "Roche") @@ -3197,7 +3145,7 @@ create.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .values("Friedrich", "Schiller") // You can request any field. Also trigger-generated values .returning(AUTHOR.ID, AUTHOR.CREATION_DATE) - .fetch();]]> + .fetch();]]>

    Some databases have poor support for returning generated keys after INSERTs. In those cases, jOOQ might need to issue another in order to fetch an @@identity value. Be aware, that this can lead to race-conditions in those databases that cannot properly return generated ID values. For more information, please consider the jOOQ Javadoc for the returning() clause. @@ -3209,50 +3157,46 @@ create.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) In some occasions, you may prefer the INSERT SELECT syntax, for instance, when you copy records from one table to another:

    -create.insertInto(AUTHOR_ARCHIVE) - .select(create.selectFrom(AUTHOR).where(AUTHOR.DECEASED.isTrue())); - -
    +create.insertInto(AUTHOR_ARCHIVE) + .select(create.selectFrom(AUTHOR).where(AUTHOR.DECEASED.isTrue()));
    The UPDATE statement - +

    The UPDATE statement is used to modify one or several pre-existing records in a database table. UPDATE statements are only possible on single tables. Support for multi-table updates will be implemented in the near future. An example update query is given here:

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

    Most databases allow for using scalar subselects in UPDATE statements in one way or another. jOOQ models this through a set(Field<T>, Select<? extends Record1<T>>) method in the UPDATE DSL API:

    - + UPDATE AUTHOR SET FIRST_NAME = ( SELECT FIRST_NAME FROM PERSON WHERE PERSON.ID = AUTHOR.ID ), - WHERE ID = 3; -create.update(AUTHOR) + WHERE ID = 3;create.update(AUTHOR) .set(AUTHOR.FIRST_NAME, select(PERSON.FIRST_NAME) .from(PERSON) .where(PERSON.ID.equal(AUTHOR.ID)) ) .where(AUTHOR.ID.equal(3)); - +

    Using row value expressions in an UPDATE statement

    @@ -3260,37 +3204,35 @@ create.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) jOOQ supports formal in various contexts, among which the UPDATE statement. Only one row value expression can be updated at a time. Here's an example:

    - + UPDATE AUTHOR SET (FIRST_NAME, LAST_NAME) = ('Hermann', 'Hesse') - WHERE ID = 3; -create.update(AUTHOR) + WHERE ID = 3;create.update(AUTHOR) .set(row(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME), row("Herman", "Hesse")) .where(AUTHOR.ID.equal(3)); - +

    This can be particularly useful when using subselects:

    - + UPDATE AUTHOR SET (FIRST_NAME, LAST_NAME) = ( SELECT PERSON.FIRST_NAME, PERSON.LAST_NAME FROM PERSON WHERE PERSON.ID = AUTHOR.ID ) - WHERE ID = 3; -create.update(AUTHOR) + WHERE ID = 3;create.update(AUTHOR) .set(row(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME), select(PERSON.FIRST_NAME, PERSON.LAST_NAME) .from(PERSON) .where(PERSON.ID.equal(AUTHOR.ID)) ) .where(AUTHOR.ID.equal(3)); - +

    The above row value expressions usages are completely typesafe. @@ -3301,45 +3243,43 @@ create.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) The Firebird and Postgres databases support a RETURNING clause on their UPDATE statements, similar as the RETURNING clause in . This is useful to fetch trigger-generated values in one go. An example is given here:

    - + - - +

    The UPDATE .. RETURNING clause is currently not simulated for other databases. Future versions might execute an additional to fetch results.

    -
    +
    The DELETE statement - +

    The DELETE statement physically removes records from a database table. DELETE statements are only possible on single tables. Support for multi-table deletes will be implemented in the near future. An example delete query is given here:

    - + DELETE AUTHOR - WHERE ID = 100; -create.delete(AUTHOR) + WHERE ID = 100;create.delete(AUTHOR) .where(AUTHOR.ID.equal(100)); - + -
    +
    The 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)

    @@ -3347,15 +3287,14 @@ RETURNING UPDATE_COUNT]]> 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 {jooq-version}, 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 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(AUTHOR) +WHEN NOT MATCHED THEN INSERT (LAST_NAME) VALUES ('Hitchcock')create.mergeInto(AUTHOR) .using(create().selectOne()) .on(AUTHOR.LAST_NAME.equal("Hitchcock")) .whenMatchedThenUpdate() @@ -3363,27 +3302,26 @@ WHEN NOT MATCHED THEN INSERT (LAST_NAME) VALUES ('Hitchcock') .whenNotMatchedThenInsert(AUTHOR.LAST_NAME) .values("Hitchcock"); - +

    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 AUTHOR (FIRST_NAME, LAST_NAME) KEY (LAST_NAME) -VALUES ('John', 'Hitchcock') -create.mergeInto(AUTHOR, +VALUES ('John', 'Hitchcock')create.mergeInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .key(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:
    @@ -3394,12 +3332,12 @@ VALUES ('John', 'Hitchcock')

    Much like the , the MERGE statement's VALUES() clause provides typesafety for degrees up to {max-row-degree}, in both the standard syntax variant as well as the H2 variant.

    -
    +
    The TRUNCATE statement - +

    The TRUNCATE statement is the only DDL statement supported by jOOQ so far. It is popular in many databases when you want to bypass constraints for table truncation. Databases may behave differently, when a truncated table is referenced by other tables. For instance, they may fail if records from a truncated table are referenced, even with ON DELETE CASCADE clauses in place. Please, consider your database manual to learn more about its TRUNCATE implementation.

    @@ -3407,44 +3345,42 @@ VALUES ('John', 'Hitchcock') The TRUNCATE syntax is trivial:

    - - TRUNCATE TABLE AUTHOR; - create.truncate(AUTHOR).execute(); - + + TRUNCATE TABLE AUTHOR;create.truncate(AUTHOR).execute(); +

    TRUNCATE is not supported by Ingres and SQLite. jOOQ will execute a DELETE FROM AUTHOR statement instead.

    -
    +
    Table expressions - +

    The following sections explain the various types of table expressions supported by jOOQ

    -
    +
    Generated Tables - +

    Most of the times, when thinking about a you're probably thinking about an actual physical table in your database schema. If you're using jOOQ's , you will have all tables from your database schema available to you as type safe Java objects. You can then use these tables in SQL , or in other , just like any other table expression. An example is given here:

    - + - + .on(AUTHOR.ID.equal(BOOK.AUTHOR_ID));]]>

    The above example shows how AUTHOR and BOOK tables are joined in a . It also shows how you can access physical by dereferencing the relevant Java attributes of their tables. @@ -3452,17 +3388,17 @@ ON (AUTHOR.ID = BOOK.AUTHOR_ID)]]>

    See the manual's section about for more information about what is really generated by the

    -
    +
    Aliased Tables - +

    The strength of jOOQ's becomes more obvious when you perform table aliasing and dereference fields from generated aliased tables. This can best be shown by example:

    - 1920 AND a.first_name = 'Paulo' - ORDER BY b.title]]> - + .orderBy(b.TITLE);]]>

    As you can see in the above example, calling as() on generated tables returns an object of the same type as the table. This means that the resulting object can be used to dereference fields from the aliased table. This is quite powerful in terms of having your Java compiler check the syntax of your SQL statements. If you remove a column from a table, dereferencing that column from that table alias will cause compilation errors. @@ -3494,40 +3429,40 @@ create.select() Only few table expressions provide the SQL syntax typesafety as shown above, where generated tables are used. Most tables, however, expose their fields through field() methods:

    - a = AUTHOR.as("a"); // Get fields from a: Field id = a.field("ID"); -Field firstName = a.field("FIRST_NAME");]]> +Field firstName = a.field("FIRST_NAME");]]>

    Derived column lists

    The SQL standard specifies how a table can be renamed / aliased in one go along with its columns. It references the term "derived column list" for the following syntax (as supported by Postgres, for instance):

    - +) t(a, b)]]>

    This feature is useful in various use-cases where column names are not known in advance (but the table's degree is!). An example for this are , or the :

    - +FROM VALUES(1, 2),(3, 4) t(a, b)]]>

    Only few databases really support such a syntax, but fortunately, jOOQ can simulate it easily using UNION ALL and an empty dummy record specifying the new column names. The two statements are equivalent:

    - +) t]]>

    In jOOQ, you would simply specify a varargs list of column aliases as such:

    - -
    +).as("t", "a", "b"));]]>
    Joined tables - +

    The that can be used in are the most powerful and best supported means of creating new in SQL. Informally, the following can be said:

    -A(colA1, ..., colAn) "join" B(colB1, ..., colBm) "produces" C(colA1, ..., colAn, colB1, ..., colBm) +A(colA1, ..., colAn) "join" B(colB1, ..., colBm) "produces" C(colA1, ..., colAn, colB1, ..., colBm)

    SQL and relational algebra distinguish between at least the following JOIN types (upper-case: SQL, lower-case: relational algebra): @@ -3580,7 +3514,7 @@ create.select().from(values( jOOQ supports all of these JOIN types (except semi-join and anti-join) directly on any :

    - table) // Various overloaded INNER JOINs @@ -3603,29 +3537,28 @@ Table crossJoin(TableLike) // Various overloaded NATURAL JOINs Table naturalJoin(TableLike) Table naturalLeftOuterJoin(TableLike) -Table naturalRightOuterJoin(TableLike)]]> +Table naturalRightOuterJoin(TableLike)]]>

    Note that most of jOOQ's JOIN operations give way to a similar DSL API hierarchy as previously seen in the manual's section about the

    -
    +
    The VALUES() table constructor - +

    Some databases allow for expressing in-memory temporary tables using a VALUES() constructor. This constructor usually works the same way as the VALUES() clause known from the or from the . With jOOQ, you can also use the VALUES() table constructor, to create tables that can be used in a :

    - + - - +

    Note, that it is usually quite useful to provide column aliases ("derived column lists") along with the table alias for the VALUES() constructor. @@ -3635,7 +3568,7 @@ FROM VALUES(1, 'a'), The above statement is simulated by jOOQ for those databases that do not support the VALUES() constructor, natively (actual simulations may vary):

    - -
    +]]>
    Nested SELECTs - +

    A can appear almost anywhere a can. Such a "nested SELECT" is often called a "derived table". Apart from many convenience methods accepting objects directly, a SELECT statement can always be transformed into a object using the asTable() method.

    Example: Scalar subquery

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

    Example: Derived table

    - + - nested = +]]> nested = create.select(BOOK.AUTHOR_ID, count().as("books")) .from(BOOK) .groupBy(BOOK.AUTHOR_ID).asTable("nested"); @@ -3702,10 +3632,10 @@ ORDER BY nested.books DESC create.select(nested.getFields()) .from(nested) .orderBy(nested.getField("books"));]]> - +

    Example: Correlated subquery

    - + - +]]> Field books = create.selectCount() .from(BOOK) @@ -3725,52 +3654,52 @@ Field books = create.select(AUTHOR.ID, books) .from(AUTHOR) .orderBy(books, AUTHOR.ID));]]> - - + +
    The Oracle 11g PIVOT clause - +

    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 .. +-- SELECT .. FROM table PIVOT (aggregateFunction [, aggregateFunction] FOR column IN (expression [, expression])) --- WHERE .. +-- WHERE ..

    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 slightly different PIVOT clause will be added later. Also, jOOQ may simulate PIVOT for other dialects in the future.

    -
    +
    jOOQ's relational division syntax - +

    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 +Assume the following cross join / cartesian product C = A × B Then it can be said that A = C ÷ B -B = C ÷ A +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) +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" +SELECT DISTINCT C.TEXT FROM C "c1" WHERE NOT EXISTS ( SELECT 1 FROM B WHERE NOT EXISTS ( @@ -3778,7 +3707,7 @@ WHERE NOT EXISTS ( 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. @@ -3792,13 +3721,13 @@ WHERE NOT EXISTS (

  • http://en.wikipedia.org/wiki/Relational_algebra#Division
  • http://www.simple-talk.com/sql/t-sql-programming/divided-we-stand-the-sql-of-relational-division/
  • -
    +
    Array and cursor unnesting - +

    The SQL standard specifies how SQL databases should implement ARRAY and TABLE types, as well as CURSOR types. Put simply, a CURSOR is a pointer to any materialised . Depending on the cursor's features, this table expression can be scrolled through in both directions, records can be locked, updated, removed, inserted, etc. Often, CURSOR types contain s, whereas ARRAY and TABLE types contain simple scalar values, although that is not a requirement

    @@ -3812,21 +3741,20 @@ WHERE NOT EXISTS ( The real power of these types become more obvious when you fetch them from to unnest them as and use them in your . An example is given here, where Oracle's DBMS_XPLAN package is used to fetch a cursor containing data about the most recent execution plan:

    - + - - +

    Note, in order to access the DbmsXplan package, you can use the to generate Oracle's SYS schema.

    -
    +
    The DUAL table - +

    The SQL standard specifies that the is optional in a . However, according to the standard, you may then no longer use some other clauses, such as the . In the real world, there exist three types of databases:

    @@ -3839,7 +3767,7 @@ FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(null, null, 'ALLSTATS'));]]> With jOOQ, you don't have to worry about the above distinction of SQL dialects. jOOQ never requires a FROM clause, but renders the necessary "DUAL" table, if needed. The following program shows how jOOQ renders "DUAL" tables

    - + - - +

    Note, that some databases (H2, MySQL) can normally do without "DUAL". However, there exist some corner-cases with complex nested SELECT statements, where this will cause syntax errors (or parser bugs). To stay on the safe side, jOOQ will always render "dual" in those dialects.

    -
    +
    Column expressions - +

    Column expressions can be used in various SQL clauses in order to refer to one or several columns. This chapter explains how to form various types of column expressions with jOOQ. A particular type of column expression is given in the section about , where an expression may have a degree of more than one.

    @@ -3891,7 +3818,7 @@ DSL.using(SQLDialect.SYBASE ).selectOne().getSQL();]]> jOOQ allows you to freely create arbitrary column expressions using a fluent expression construction API. Many expressions can be formed as functions from , other expressions can be formed based on a pre-existing column expression. For example:

    - field1 = BOOK.TITLE; // A function created from the DSL using "prefix" notation @@ -3903,31 +3830,30 @@ Field field3 = BOOK.TITLE.trim(); // More complex function with advanced DSL syntax Field field4 = listAgg(BOOK.TITLE) .withinGroupOrderBy(BOOK.ID.asc()) - .over().partitionBy(AUTHOR.ID);]]> + .over().partitionBy(AUTHOR.ID);]]>

    In general, it is up to you whether you want to use the "prefix" notation or the "postfix" notation to create new column expressions based on existing ones. The "SQL way" would be to use the "prefix notation", with functions created from the . The "Java way" or "object-oriented way" would be to use the "postfix" notation with functions created from objects. Both ways ultimately create the same query part, though.

    -
    +
    Table columns - +

    Table columns are the most simple implementations of a . They are mainly produced by jOOQ's and can be dereferenced from the generated tables. This manual is full of examples involving table columns. Another example is given in this query:

    - + - - +

    Table columns implement a more specific interface called , which is parameterised with its associated <R extends Record> record type. @@ -3935,45 +3861,43 @@ ORDER BY BOOK.TITLE]]>

    See the manual's section about for more information about what is really generated by the

    -
    +
    Aliased columns - +

    Just like , columns can be renamed using aliases. Here is an example:

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

    Here is how it's done with jOOQ:

    -Record record = create.select( +Record record = create.select( concat(AUTHOR.FIRST_NAME, val(" "), AUTHOR.LAST_NAME).as("author"), count().as("books")) .from(AUTHOR) .join(BOOK).on(AUTHOR.ID.equal(BOOK.AUTHOR_ID)) - .groupBy(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME).fetchAny(); + .groupBy(AUTHOR.FIRST_NAME, 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")); - -
    +System.out.println("Author : " + record.getValue("author")); +System.out.println("Books : " + record.getValue("books"));
    Cast expressions - +

    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 , but can also be any of , , , , , , .

    @@ -3981,27 +3905,27 @@ System.out.println("Books : " + record.getValue("books")); Sometimes, this automatic mapping might not be what you needed, or jOOQ cannot know the type of a field. In those cases you would write SQL type CAST like this:

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

    in jOOQ, you can write something like that:

    -create.select(TAuthor.LAST_NAME.cast(PostgresDataType.TEXT)); +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)); +create.select(TAuthor.LAST_NAME.cast(String.class));

    The complete CAST API in consists of these three methods:

    - { + { // Cast this field to the type of another field Field cast(Field field); @@ -4021,19 +3945,18 @@ public class DSL { Field castNull(Field field); Field castNull(DataType type); Field castNull(Class type); -}]]> -
    +}]]>
    Datatype coercions - +

    A slightly different use case than are data type coercions, which are not rendered through to generated SQL. Sometimes, you may want to pretend that a numeric value is really treated as a string value, for instance when binding a numeric :

    - field1 = val(1).coerce(String.class); -Field field2 = val("1").coerce(Integer.class);]]> + field1 = val(1).coerce(String.class); +Field field2 = val("1").coerce(Integer.class);]]>

    In the above example, field1 will be treated by jOOQ as a Field<String>, binding the numeric literal 1 as a VARCHAR value. The same applies to field2, whose string literal "1" will be bound as an INTEGER value. @@ -4042,40 +3965,39 @@ Field field2 = val("1").coerce(Integer.class);]]>

    This technique is better than performing unsafe or rawtype casting in Java, if you cannot access the "right" field type from any given expression.

    -
    +
    Arithmetic expressions - +

    Numeric arithmetic expressions

    Your database can do the math for you. 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 +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); +create.select(val(1).add(2).mul(val(5).sub(3)).div(2).mod(10);

    Datetime arithmetic expressions

    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)); - + + SELECT SYSDATE + 3 FROM DUAL;create.select(currentTimestamp().add(3)); +

    For more advanced datetime arithmetic, use the DSL's timestampDiff() and dateDiff() functions, as well as jOOQ's built-in SQL standard INTERVAL data type support: @@ -4084,31 +4006,30 @@ Field field2 = val("1").coerce(Integer.class);]]>

  • INTERVAL YEAR TO MONTH:
  • INTERVAL DAY TO SECOND:
  • -
    +
    String concatenation - +

    The SQL standard defines the concatenation operator to be an infix operator, similar to the ones we've seen in the chapter about . This operator looks like this: ||. Some other dialects do not support this operator, but expect a concat() function, instead. jOOQ renders the right operator / function, depending on your :

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

    There are a variety of general functions supported by jOOQ As discussed in the chapter about functions are mostly simulated in your database, in case they are not natively supported.

    @@ -4125,12 +4046,12 @@ create.select(concat("A", "B", "C"));

    Please refer to the for more details.

    -
    +
    Numeric functions - +

    Math can be done efficiently in the database before returning results to your Java application. In addition to the discussed previously, jOOQ also supports a variety of numeric functions. As discussed in the chapter about numeric functions (as any function type) are mostly simulated in your database, in case they are not natively supported.

    @@ -4172,12 +4093,12 @@ create.select(concat("A", "B", "C"));

    Please refer to the for more details.

    -
    +
    Bitwise functions - +

    Interestingly, bitwise functions and bitwise arithmetic is not very popular among SQL databases. Most databases only support a few bitwise operations, while others ship with the full set of operators. jOOQ's API includes most bitwise operations as listed below. In order to avoid ambiguities with , all bitwise functions are prefixed with "bit"

    @@ -4200,12 +4121,12 @@ create.select(concat("A", "B", "C")); http://blog.jooq.org/2011/10/30/the-comprehensive-sql-bitwise-operations-compatibility-list/

    -
    +
    String functions - +

    String formatting can be done efficiently in the database before returning results to your Java application. As discussed in the chapter about string functions (as any function type) are mostly simulated in your database, in case they are not natively supported.

    @@ -4243,18 +4164,18 @@ create.select(concat("A", "B", "C")); Various databases have some means of searching through columns using regular expressions if the does not provide sufficient pattern matching power. While there are many different functions and operators in the various databases, jOOQ settled for the SQL:2008 standard REGEX_LIKE operator. Being an operator (and not a function), you should use the corresponding method on :

    - +

    Note that the SQL standard specifies that patterns should follow the XQuery standards. In the real world, the POSIX regular expression standard is the most used one, some use Java regular expressions, and only a few ones use Perl regular expressions. jOOQ does not make any assumptions about regular expression syntax. For cross-database compatibility, please read the relevant database manuals carefully, to learn about the appropriate syntax. Please refer to the for more details.

    -
    +
    Date and time functions - +

    This is a list of date and time functions supported by jOOQ's :

    @@ -4273,29 +4194,29 @@ create.select(concat("A", "B", "C"));

    jOOQ fills a gap opened by JDBC, which neglects an important SQL data type as defined by the SQL standards: INTERVAL types. See the manual's section about for more details.

    -
    +
    System functions - +

    This is a list of system functions supported by jOOQ's :

    • CURRENT_USER: Get current user.
    -
    +
    Aggregate functions - +

    Aggregate functions work just like functions, even if they have a slightly different semantics. Here are some example aggregate functions from the :

    - count(); AggregateFunction count(Field field); AggregateFunction max (Field field); @@ -4332,20 +4253,19 @@ AggregateFunction regrR2 (Field y, Field regrSlope (Field y, Field x); AggregateFunction regrSXX (Field y, Field x); AggregateFunction regrSXY (Field y, Field x); -AggregateFunction regrSYY (Field y, Field x);]]> +AggregateFunction regrSYY (Field y, Field x);]]>

    Here's an example, counting the number of books any author has written:

    - + SELECT AUTHOR_ID, COUNT(*) FROM BOOK -GROUP BY AUTHOR_ID -create.select(BOOK.AUTHOR_ID, count()) +GROUP BY AUTHOR_IDcreate.select(BOOK.AUTHOR_ID, count()) .from(BOOK) .groupBy(BOOK.AUTHOR_ID); - +

    Aggregate functions have strong limitations about when they may be used and when not. For instance, you can use aggregate functions in scalar queries. Typically, this means you only select aggregate functions, no or other . Another use case is to use them along with a as seen in the previous example. Note, that jOOQ does not check whether your using of aggregate functions is correct according to the SQL standards, or according to your database's behaviour. @@ -4355,39 +4275,37 @@ GROUP BY AUTHOR_ID

    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 Oracle's LISTAGG() (also known as GROUP_CONCAT in other ). 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, ", ") +GROUP BY AUTHOR_IDcreate.select(listAgg(BOOK.TITLE, ", ") .withinGroupOrderBy(BOOK.TITLE)) .from(BOOK) .groupBy(BOOK.AUTHOR_ID) - +

    The above query might yield:

    -+---------------------+ ++---------------------+ | LISTAGG | +---------------------+ | 1984, Animal Farm | | O Alquimista, Brida | -+---------------------+ ++---------------------+

    FIRST and LAST: Oracle's "ranked" aggregate functions

    Oracle allows for restricting aggregate functions using the KEEP() clause, which is supported by jOOQ. In Oracle, some aggregate functions (MIN, MAX, SUM, AVG, COUNT, VARIANCE, or STDDEV) can be restricted by this clause, hence also allows for specifying it. Here are a couple of examples using this clause:

    - + SUM(BOOK.AMOUNT_SOLD) - KEEP(DENSE_RANK FIRST ORDER BY BOOK.AUTHOR_ID) -sum(BOOK.AMOUNT_SOLD) + KEEP(DENSE_RANK FIRST ORDER BY BOOK.AUTHOR_ID)sum(BOOK.AMOUNT_SOLD) .keepDenseRankFirstOrderBy(BOOK.AUTHOR_ID) - +

    User-defined aggregate functions

    @@ -4398,12 +4316,12 @@ GROUP BY AUTHOR_ID

    In those databases that support , jOOQ's can be transformed into a window function / analytical function by calling over() on it. See the manual's section about for more details.

    -
    +
    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. Note, that H2 and HSQLDB have implemented ROW_NUMBER() functions, without true windowing support.

    @@ -4411,7 +4329,7 @@ GROUP BY AUTHOR_ID As previously discussed, any can be transformed into a window function using the over() method. See the chapter about for details. In addition to those, there are also some more window functions supported by jOOQ, as declared in the :

    - rowNumber(); WindowOverStep rank(); WindowOverStep denseRank(); @@ -4431,7 +4349,7 @@ GROUP BY AUTHOR_ID // Statistical functions WindowOverStep cumeDist(); - WindowOverStep ntile(int number);]]> + WindowOverStep ntile(int number);]]>

    SQL distinguishes between various window function types (e.g. "ranking functions"). Depending on the function, SQL expects mandatory PARTITION BY or ORDER BY clauses within the OVER() clause. jOOQ does not enforce those rules for two reasons: @@ -4448,7 +4366,7 @@ GROUP BY AUTHOR_ID Here are some simple examples of window functions with jOOQ:

    - + -- Sample uses of ROW_NUMBER() ROW_NUMBER() OVER() ROW_NUMBER() OVER(PARTITION BY 1) @@ -4459,8 +4377,7 @@ ROW_NUMBER() OVER(PARTITION BY BOOK.AUTHOR_ID ORDER BY BOOK.ID) FIRST_VALUE(BOOK.ID) OVER() FIRST_VALUE(BOOK.ID IGNORE NULLS) OVER() FIRST_VALUE(BOOK.ID RESPECT NULLS) OVER() - -// Sample uses of rowNumber() +// Sample uses of rowNumber() rowNumber().over() rowNumber().over().partitionByOne() rowNumber().over().partitionBy(BOOK.AUTHOR_ID) @@ -4471,27 +4388,26 @@ firstValue(BOOK.ID).over() firstValue(BOOK.ID).ignoreNulls().over() firstValue(BOOK.ID).respectNulls().over() - +

    An advanced window function example

    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). Window functions are accessible from the previously seen 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, + FROM transactionscreate.select(t.BOOKED_AT, t.AMOUNT, sum(t.AMOUNT).over().partitionByOne() .orderBy(t.BOOKED_AT) .rowsBetweenUnboundedPreceding() .andCurrentRow().as("total") .from(TRANSACTIONS.as("t")); - +

    Window functions created from ordered aggregate functions

    @@ -4499,48 +4415,46 @@ firstValue(BOOK.ID).respectNulls().over() In the previous chapter about , we have seen the concept of "ordered aggregate functions", such as Oracle's LISTAGG(). These functions have a window function / analytical function variant, as well. For example:

    - + SELECT LISTAGG(TITLE, ', ') WITHIN GROUP (ORDER BY TITLE) OVER (PARTITION BY BOOK.AUTHOR_ID) -FROM BOOK -create.select(listAgg(BOOK.TITLE, ", ") +FROM BOOKcreate.select(listAgg(BOOK.TITLE, ", ") .withinGroupOrderBy(BOOK.TITLE) .over().partitionBy(BOOK.AUTHOR_ID)) .from(BOOK) - +

    Window functions created from Oracle's FIRST and LAST aggregate functions

    In the previous chapter about , we have seen the concept of "FIRST and LAST aggregate functions". These functions have a window function / analytical function variant, as well. For example:

    - + SUM(BOOK.AMOUNT_SOLD) KEEP(DENSE_RANK FIRST ORDER BY BOOK.AUTHOR_ID) - OVER(PARTITION BY 1) -sum(BOOK.AMOUNT_SOLD) + OVER(PARTITION BY 1)sum(BOOK.AMOUNT_SOLD) .keepDenseRankFirstOrderBy(BOOK.AUTHOR_ID) .over().partitionByOne() - +

    Window functions created from user-defined aggregate functions

    User-defined aggregate functions also implement , hence they can also be transformed into window functions using over(). This is supported by Oracle in particular. See the manual's section about for more details.

    -
    +
    Grouping functions - +

    ROLLUP() explained in SQL

    The SQL standard defines special functions that can be used in the : the grouping functions. These functions can be used to generate several groupings in a single clause. This can best be explained in SQL. Let's take ROLLUP() for instance:

    - + - - +

    In English, the ROLLUP() grouping function provides N+1 groupings, when N is the number of arguments to the ROLLUP() function. Each grouping has an additional group field from the ROLLUP() argument field list. The results of the second query might look something like this:

    - ++-----------+--------------+----------+]]>

    CUBE() explained in SQL

    CUBE() is different from ROLLUP() in the way that it doesn't just create N+1 groupings, it creates all 2^N possible combinations between all group fields in the CUBE() function argument list. Let's re-consider our second query from before:

    - + - - +

    The results would then hold:

    - ++-----------+--------------+----------+]]>

    GROUPING SETS()

    @@ -4669,7 +4581,7 @@ ORDER BY 1 NULLS FIRST, 2 NULLS FIRST jOOQ fully supports all of these functions, as well as the utility functions GROUPING() and GROUPING_ID(), used for identifying the grouping set ID of a record. The thus includes:

    -... fields); GroupField cube(Field... fields); GroupField groupingSets(Field... fields); @@ -4678,66 +4590,64 @@ GroupField groupingSets(Collection>... fields); // The utility functions generating IDs per GROUPING SET Field grouping(Field); -Field groupingId(Field...);]]> +Field groupingId(Field...);]]>

    MySQL's and CUBRID's WITH ROLLUP syntax

    MySQL and CUBRID don't know any grouping functions, but they support a WITH ROLLUP clause, that is equivalent to simple ROLLUP() grouping functions. jOOQ simulates ROLLUP() in MySQL and CUBRID, by rendering this WITH ROLLUP clause. The following two statements mean the same:

    - + - - -
    + +
    User-defined functions - +

    Some databases support user-defined functions, which can be embedded in any SQL statement, if you're using jOOQ's . Let's say you have the following simple function in Oracle SQL:

    - +]]>

    The above function will be made available from a generated class. You can use it like any other :

    - - - - + + +

    Note that user-defined functions returning or data types can also be used wherever can be used, if they are

    -
    +
    User-defined aggregate functions - +

    Some databases support user-defined aggregate functions, which can then be used along with or as . An example for such a database is Oracle. With Oracle, you can define the following OBJECT type (the example was taken from the Oracle 11g documentation):

    - +END;]]>

    The above OBJECT type is then available to function declarations as such:

    - +PARALLEL_ENABLE AGGREGATE USING U_SECOND_MAX;]]>

    Using the generated aggregate function

    jOOQ's will detect such aggregate functions and generate them differently from regular . They implement the type, as mentioned in the manual's section about . Here's how you can use the SECOND_MAX() aggregate function with jOOQ:

    - + - - -
    + +
    The CASE expression - +

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

    - + - - +

    In jOOQ, both syntaxes are supported (The second one is simulated in Derby, which only knows the first one). 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. @@ -4854,15 +4762,15 @@ create.decode().value(AUTHOR.FIRST_NAME) A CASE expression can be used anywhere where you can place a . For instance, you can SELECT the above expression, if you're selecting from AUTHOR:

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

    The Oracle DECODE() function

    Oracle knows a more succinct, but maybe less readable DECODE() function with a variable number of arguments. This function roughly does the same as the second case expression syntax. jOOQ supports the DECODE() function and simulates it using CASE expressions in all dialects other than Oracle:

    - + - - +

    CASE clauses in an ORDER BY clause

    Sort indirection is often implemented with a CASE clause of a SELECT's ORDER BY clause. See the manual's section about the for more details.

    -
    +
    Sequences and serials - +

    Sequences implement the interface, providing essentially this functionality:

    - currval(); // Get a field for the NEXTVAL sequence property -Field nextval();]]> +Field nextval();]]>

    So if you have a sequence like this in Oracle:

    -CREATE SEQUENCE s_author_id +CREATE SEQUENCE s_author_id

    You can then use your object directly in a SQL statement as such:

    - +]]>
    • For more information about generated sequences, refer to the manual's section about
    • For more information about executing standalone calls to sequences, refer to the manual's section about
    -
    +
    Tuples or row value expressions - +

    According to the SQL standard, row value expressions can have a degree of more than one. This is commonly used in the , where the VALUES row value constructor allows for providing a row value expression as a source for INSERT data. Row value expressions can appear in various other places, though. They are supported by jOOQ as records / rows. jOOQ's allows for the construction of type-safe records up to the degree of {max-row-degree}. Higher-degree Rows are supported as well, but without any type-safety. Row types are modelled as follows:

    - Row1 row(T1 t1) { ... } public static Row2 row(T1 t1, T2 t2) { ... } public static Row3 row(T1 t1, T2 t2, T3 t3) { ... } @@ -4947,7 +4854,7 @@ public static Row4 row(T1 t1, T2 t2, T3 t3, T4 // [ ... idem for Row5, Row6, Row7, ..., Row{max-row-degree} ] // Degrees of more than {max-row-degree} are supported without type-safety -public static RowN row(Object... values) { ... }]]> +public static RowN row(Object... values) { ... }]]>

    Using row value expressions in predicates

    @@ -4973,14 +4880,14 @@ public static RowN row(Object... values) { ... }]]>

    jOOQ chose to explicitly support degrees up to {max-row-degree} to match Scala's typesafe tuple, function and product support. Unlike Scala, however, jOOQ also supports higher degrees without the additional typesafety.

    -
    +
    Conditional expressions - +

    Conditions or conditional expressions are widely used in SQL and in the jOOQ API. They can be used in

    @@ -5017,22 +4924,21 @@ public static RowN row(Object... values) { ... }]]>

    Note that jOOQ does not model these values as actual compatible.

    -
    +
    Condition building - +

    With jOOQ, most are built from , calling various methods on them. For instance, to build a , you can write the following expression:

    - + - - +

    Create conditions from the DSL

    @@ -5048,48 +4954,47 @@ BOOK.TITLE.notEqual("Animal Farm")]]>

    Conditions can also be connected using as will be discussed in a subsequent chapter.

    -
    +
    AND, OR, NOT boolean operators - +

    In SQL, as in most other languages, can be connected using the AND and OR binary operators, as well as the NOT unary operator, to form new conditional expressions. In jOOQ, this is modelled as such:

    - + - - +

    The above example shows that the number of parentheses in Java can quickly explode. Proper indentation may become crucial in making such code readable. In order to understand how jOOQ composes combined conditional expressions, let's assign component expressions first:

    - +Condition combined2 = combined1.andNot(c); // The left-hand side of the AND NOT () operator is already wrapped in parentheses]]>

    The Condition API

    Here are all boolean operators on the interface:

    -) // Combine conditions with OR. Convenience for adding orNot(Condition) // Combine conditions with OR. Convenience for adding an inverted condition to the rhs orNotExists(Select) // Combine conditions with OR. Convenience for adding an inverted exists predicate to the rhs -not() // Invert a condition (synonym for DSL.not(Condition)]]> -
    +not() // Invert a condition (synonym for DSL.not(Condition)]]>
    Comparison predicate - +

    In SQL, comparison predicates are formed using common comparison operators:

    @@ -5128,7 +5032,7 @@ not() // Invert a condition (synonym for DSL.not(Condition)] Unfortunately, Java does not support operator overloading, hence these operators are also implemented as methods in jOOQ, like any other SQL syntax elements. The relevant parts of the interface are these:

    -); // = (some column expression) eq or equal(Select>); // = (some scalar SELECT statement) ne or notEqual(T); // <> (some bind value) @@ -5145,7 +5049,7 @@ gt or greaterThan(Field); // > (some column expressio gt or greaterThan(Select>); // > (some scalar SELECT statement) ge or greaterOrEqual(T); // >= (some bind value) ge or greaterOrEqual(Field); // >= (some column expression) -ge or greaterOrEqual(Select>); // >= (some scalar SELECT statement)]]> +ge or greaterOrEqual(Select>); // >= (some scalar SELECT statement)]]>

    Note that every operator is represented by two methods. A verbose one (such as equal()) and a two-character one (such as eq()). Both methods are the same. You may choose either one, depending on your taste. The manual will always use the more verbose one. @@ -5156,25 +5060,24 @@ ge or greaterOrEqual(Select>); // >= (some scalar SELECT st In addition to the above, jOOQ provides a few convenience methods for common operations performed on strings using comparison predicates:

    - + LOWER('animal farm')]]> - LOWER('animal farm')]]> - -
    + +
    Comparison predicate (degree > 1) - +

    All variants of the that we've seen in the previous chapter also work for . If your database does not support row value expression comparison predicates, jOOQ simulates them the way they are defined in the SQL standard:

    - + (A, B) <> (X, Y) (A, B) < (X, Y) -(A, B) <= (X, Y)]]> - NOT((A, B) = (X, Y)) NOT((A, B) >= (X, Y)) NOT((A, B) > (X, Y))]]> - +

    jOOQ supports all of the above row value expression comparison predicates, both with and at the right-hand side:

    - + (X, Y))]]> SELECT PERSON.ID, 'Animal Farm' FROM PERSON WHERE PERSON.ID = 1 -)]]> - - -
    + +
    Quantified comparison predicate - +

    If the right-hand side of a turns out to be a non-scalar table subquery, you can wrap that subquery in a quantifier, such as ALL, ANY, or SOME. Note that the SQL standard defines ANY and SOME to be equivalent. jOOQ settled for the more intuitive ANY and doesn't support SOME. Here are some examples, supported by jOOQ:

    - + ALL(1920, 1940)]]> - ALL(1920, 1940)]]> - +

    For the example, the right-hand side of the quantified comparison predicates were filled with argument lists. But it is easy to imagine that the source of values results from a . @@ -5271,63 +5171,60 @@ BOOK.PUBLISHED_IN.greaterThan(all(1920, 1940));]]> It is interesting to note that the SQL standard defines the in terms of the ANY-quantified predicate. The following two expressions are equivalent:

    - - - - + + +

    Typically, the is more readable than the quantified comparison predicate.

    -
    +
    NULL predicate - +

    In SQL, you cannot compare NULL with any value using , as the result would yield NULL again, which is neither TRUE nor FALSE (see also the manual's section about ). In order to test a for NULL, use the NULL predicate as such:

    - + - - + -
    +
    NULL predicate (degree > 1) - +

    The SQL NULL predicate also works well for , although it has some subtle, counter-intuitive features when it comes to inversing predicates with the NOT() operator! Here are some examples:

    - + - - +

    The SQL standard contains a nice truth table for the above rules:

    -+-----------------------+-----------+---------------+---------------+-------------------+ ++-----------------------+-----------+---------------+---------------+-------------------+ | Expression | R IS NULL | R IS NOT NULL | NOT R IS NULL | NOT R IS NOT NULL | +-----------------------+-----------+---------------+---------------+-------------------+ | degree 1: null | true | false | false | true | @@ -5335,21 +5232,19 @@ NOT((A, B) IS NOT NULL)]]> | degree > 1: all null | true | false | false | true | | degree > 1: some null | false | false | true | true | | degree > 1: none null | false | true | true | false | -+-----------------------+-----------+---------------+---------------+-------------------+ ++-----------------------+-----------+---------------+---------------+-------------------+

    In jOOQ, you would simply use the isNull() and isNotNull() methods on row value expressions. Again, as with the , the row value expression NULL predicate is simulated by jOOQ, if your database does not natively support it:

    - - -
    +
    DISTINCT predicate - +

    Some databases support the DISTINCT predicate, which serves as a convenient, NULL-safe . With the DISTINCT predicate, the following truth table can be assumed:

    @@ -5363,18 +5258,17 @@ row(BOOK.ID, BOOK.TITLE).isNotNull();]]> For instance, you can compare two fields for distinctness, ignoring the fact that any of the two could be NULL, which would lead to funny results. This is supported by jOOQ as such:

    - + - - +

    If your database does not natively support the DISTINCT predicate, jOOQ simulates it with an equivalent , modelling the above truth table:

    - + - - -
    + +
    BETWEEN predicate - +

    The BETWEEN predicate can be seen as syntactic sugar for a pair of . According to the SQL standard, the following two predicates are equivalent:

    - - -= [B] AND [A] <= [C]]]> - + += [B] AND [A] <= [C]]]> +

    Note the inclusiveness of range boundaries in the definition of the BETWEEN predicate. Intuitively, this is supported in jOOQ as such:

    - + - - +

    BETWEEN SYMMETRIC

    The SQL standard defines the SYMMETRIC keyword to be used along with BETWEEN to indicate that you do not care which bound of the range is larger than the other. A database system should simply swap range bounds, in case the first bound is greater than the second one. jOOQ supports this keyword as well, simulating it if necessary.

    - + - - +

    The simulation is done trivially:

    - - - - + + + -
    +
    BETWEEN predicate (degree > 1) - +

    The SQL BETWEEN predicate also works well for . Much like the , it is defined in terms of a pair of regular :

    - + -= [B] AND [A] <= [C] +[A] BETWEEN SYMMETRIC [B] AND [C]]]>= [B] AND [A] <= [C] ([A] >= [B] AND [A] <= [C]) OR ([A] >= [C] AND [A] <= [B])]]> - +

    The above can be factored out according to the rules listed in the manual's section about . @@ -5464,14 +5352,12 @@ BOOK.PUBLISHED_IN.notBetweenSymmetric(1940).and(1920)]]> jOOQ supports the BETWEEN [SYMMETRIC] predicate and simulates it in all SQL dialects where necessary. An example is given here:

    - - -
    +
    LIKE predicate - +

    LIKE predicates are popular for simple wildcard-enabled pattern matching. Supported wildcards in all SQL databases are:

    @@ -5483,24 +5369,22 @@ BOOK.PUBLISHED_IN.notBetweenSymmetric(1940).and(1920)]]> With jOOQ, the LIKE predicate can be created from any as such:

    - + - - +

    Escaping operands with the LIKE predicate

    Often, your pattern may contain any of the wildcard characters "_" and "%", in case of which you may want to escape them. jOOQ does not automatically escape patterns in like() and notLike() methods. Instead, you can explicitly define an escape character as such:

    - + - - +

    In the above predicate expressions, the exclamation mark character is passed as the escape character to escape wildcard characters "!_" and "!%", as well as to escape the escape character itself: "!!" @@ -5514,7 +5398,7 @@ BOOK.TITLE.notLike("%The !%-Sign Book%", '!')]]> In addition to the above, jOOQ provides a few convenience methods for common operations performed on strings using the LIKE predicate. Typical operations are "contains predicates", "starts with predicates", "ends with predicates", etc. Here is the full convenience API wrapping LIKE predicates:

    - + - - +

    Note, that jOOQ escapes % and _ characters in value in some of the above predicate implementations. For simplicity, this has been omitted in this manual.

    -
    +
    IN predicate - +

    In SQL, apart from comparing a value against several values, the IN predicate can be used to create semi-joins or anti-joins. jOOQ knows the following methods on the interface, to construct such IN predicates:

    -) // Construct an IN predicate from a collection of bind values +) // Construct an IN predicate from a collection of bind values in(T...) // Construct an IN predicate from bind values in(Field...) // Construct an IN predicate from column expressions in(Select>) // Construct an IN predicate from a subselect notIn(Collection) // Construct a NOT IN predicate from a collection of bind values notIn(T...) // Construct a NOT IN predicate from bind values notIn(Field...) // Construct a NOT IN predicate from column expressions -notIn(Select>) // Construct a NOT IN predicate from a subselect]]> +notIn(Select>) // Construct a NOT IN predicate from a subselect]]>

    A sample IN predicate might look like this:

    - + - - +

    NOT IN and NULL values

    @@ -5572,7 +5454,7 @@ BOOK.TITLE.notIn("Animal Farm", "1984")]]> Beware that you should probably not have any NULL values in the right hand side of a NOT IN predicate, as the whole expression would evaluate to NULL, which is rarely desired. This can be shown informally using the following reasoning:

    --- The following conditional expressions are formally or informally equivalent +-- The following conditional expressions are formally or informally equivalent A NOT IN (B, C) A != ANY(B, C) A != B AND A != C @@ -5581,37 +5463,35 @@ A != B AND A != C A NOT IN (B, NULL) -- Substitute C for NULL A != B AND A != NULL -- From the above rules A != B AND NULL -- [ANY] != NULL yields NULL -NULL -- [ANY] AND NULL yields NULL +NULL -- [ANY] AND NULL yields NULL

    A good way to prevent this from happening is to use the for anti-joins, which is NULL-value insensitive. See the manual's section about to see a boolean truth table.

    -
    +
    IN predicate (degree > 1) - +

    The SQL IN predicate also works well for . Much like the , it is defined in terms of a . The two expressions are equivalent:

    - - - - + + +

    jOOQ supports the IN predicate. Simulation of the IN predicate where row value expressions aren't well supported is currently only available for IN predicates that do not take a subselect as an IN predicate value. An example is given here:

    - -
    +
    EXISTS predicate - +

    Slightly less intuitive, yet more powerful than the previously discussed is the EXISTS predicate, that can be used to form semi-joins or anti-joins. With jOOQ, the EXISTS predicate can be formed in various ways:

    @@ -5625,16 +5505,15 @@ NULL -- [ANY] AND NULL yields NULL An example of an EXISTS predicate can be seen here:

    - + - - +

    Note that in SQL, the projection of a subselect in an EXISTS predicate is irrelevant. To help you write queries like the above, you can use jOOQ's selectZero() or selectOne() methods @@ -5645,60 +5524,59 @@ notExists(create.selectOne().from(BOOK) In theory, the two types of predicates can perform equally well. If your database system ships with a sophisticated cost-based optimiser, it will be able to transform one predicate into the other, if you have all necessary constraints set (e.g. referential constraints, not null constraints). However, in reality, performance between the two might differ substantially. An interesting blog post investigating this topic on the MySQL database can be seen here:
    http://blog.jooq.org/2012/07/27/not-in-vs-not-exists-vs-left-join-is-null-mysql/

    -
    +
    OVERLAPS predicate - +

    When comparing dates, the SQL standard allows for using a special OVERLAPS predicate, which checks whether two date ranges overlap each other. The following can be said:

    - +(DATE '2010-01-02', CAST('+2 00:00:00' AS INTERVAL DAY TO SECOND))]]>

    The OVERLAPS predicate in jOOQ

    jOOQ supports the OVERLAPS predicate on . The following methods are contained in :

    - t1, Field t2); -Condition overlaps(Row2 row);]]> +Condition overlaps(Row2 row);]]>

    This allows for expressing the above predicates as such:

    - +row(Date.valueOf('2010-01-01'), new DayToSecond(2)).overlaps(Date.valueOf('2010-01-02'), new DayToSecond(2))]]>

    jOOQ's extensions to the standard

    Unlike the standard (or any database implementing the standard), jOOQ also supports the OVERLAPS predicate for comparing arbitrary . For instance, (1, 3) OVERLAPS (2, 4) will yield true in jOOQ. This is simulated as such

    - -
    +(C <= B) AND (A <= D)]]>
    Plain SQL - +

    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 a host language (Java in this case), which was not made for exactly the same purposes as its hosted 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 by language constraints of its host language. We have seen many functionalities where the DSL becomes a bit verbose. This can be especially true for:

    @@ -5727,7 +5605,7 @@ row(Date.valueOf('2010-01-01'), new DayToSecond(2)).overlaps(Date.valueOf('2010-

    Plain SQL API methods are usually overloaded in three ways. Let's look at the condition query part constructor:

    - +Condition condition(String sql, QueryPart... parts);]]>

    Please refer to the Javadoc for more details. The following is a more complete listing of plain SQL construction methods from the DSL:

    - resultQuery(String sql, QueryPart... parts); // A query with results. This is the same as resultQuery(...).fetch(); Result fetch(String sql); Result fetch(String sql, Object... bindings); -Result fetch(String sql, QueryPart... parts);]]> +Result fetch(String sql, QueryPart... parts);]]>

    Apart from the general factory methods, plain SQL is also available 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"); @@ -5823,7 +5701,7 @@ create.select(LAST_NAME, COUNT1, COUNT2) // Use plain SQL again as fields in GROUP BY and ORDER BY clauses .groupBy(LAST_NAME) - .orderBy(LAST_NAME);]]> + .orderBy(LAST_NAME);]]>

    Important things to note about plain SQL!

    @@ -5835,12 +5713,12 @@ create.select(LAST_NAME, COUNT1, COUNT2)

  • 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.
  • -
    +
    Bind values and parameters - +

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

    @@ -5859,31 +5737,31 @@ create.select(LAST_NAME, COUNT1, COUNT2)

    The following sections explain how you can introduce bind values in jOOQ, and how you can control the way they are rendered and bound to SQL.

    -
    +
    Indexed parameters - +

    JDBC only knows indexed bind values. A typical example for using bind values with JDBC is this:

    - +stmm.executeQuery();]]>

    With dynamic SQL, keeping track of the number of question marks and their corresponding index may turn out to be hard. jOOQ abstracts this and lets you provide the bind value right where it is needed. A trivial example is this:

    - +create.select().from(BOOK).where(BOOK.ID.equal(val(5))).and(BOOK.TITLE.equal(val("Animal Farm")));]]>

    Note the using of to explicitly create an indexed bind value. You don't have to worry about that index. When the query is , each bind value will render a question mark. When the query , each bind value will generate the appropriate bind value index. @@ -5894,7 +5772,7 @@ create.select().from(BOOK).where(BOOK.ID.equal(val(5))).and(BOOK.TITLE.equal(val Should you decide to run the above query outside of jOOQ, using your own , you can do so as follows:

    - select = create.select().from(BOOK).where(BOOK.ID.equal(5)).and(BOOK.TITLE.equal("Animal Farm")); + select = create.select().from(BOOK).where(BOOK.ID.equal(5)).and(BOOK.TITLE.equal("Animal Farm")); // Render the SQL statement: String sql = select.getSQL(); @@ -5904,34 +5782,34 @@ assertEquals("SELECT * FROM BOOK WHERE ID = ? AND TITLE = ?", sql); List values = select.getBindValues(); assertEquals(2, values.size()); assertEquals(5, values.get(0)); -assertEquals("Animal Farm", values.get(1));]]> +assertEquals("Animal Farm", values.get(1));]]>

    You can also extract specific bind values by index from a query, if you wish to modify their underlying value after creating a query. This can be achieved as such:

    - select = create.select().from(BOOK).where(BOOK.ID.equal(5)).and(BOOK.TITLE.equal("Animal Farm")); + select = create.select().from(BOOK).where(BOOK.ID.equal(5)).and(BOOK.TITLE.equal("Animal Farm")); Param param = select.getParam("2"); // You could now modify the Query's underlying bind value: if ("Animal Farm".equals(param.getValue())) { param.setConverted("1984"); -}]]> +}]]>

    For more details about jOOQ's internals, see the manual's section about .

    - +
    Named parameters - +

    Some SQL access abstractions that are built on top of JDBC, or some that bypass JDBC may support named parameters. jOOQ allows you to give names to your parameters as well, although those names are not rendered to SQL strings by default. Here is an example of how to create named parameters using the type:

    - param1 = query.getParam("lastName"); @@ -5940,41 +5818,40 @@ Param param2 = param("lastName", "Poe"); Query query2 = create.select().from(AUTHOR).where(LAST_NAME.equal(param2)); // You can now change the bind value directly on the Param reference: -param2.setValue("Orwell");]]> +param2.setValue("Orwell");]]>

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

    - +query2.bind("lastName", "Orwell");]]>

    In order to actually render named parameter names in generated SQL, use the method:

    - + - - -
    + +
    Inlined parameters - +

    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:

    @@ -5990,7 +5867,7 @@ WHERE LAST_NAME = :lastName]]> In both cases, your inlined bind values will be properly escaped to avoid SQL syntax errors and SQL injection. Some examples:

    - -
    + .where(LAST_NAME.equal("Poe"));]]>
    SQL injection and plain SQL QueryParts - +

    Special care needs to be taken when using . While jOOQ's API allows you to specify bind values for use with plain SQL, you're not forced to do that. For instance, both of the following queries will lead to the same, valid result:

    - +create.fetch("SELECT * FROM BOOK WHERE ID = 5 AND TITLE = 'Animal Farm'");]]>

    All methods in the jOOQ API that allow for plain (unescaped, untreated) SQL contain a warning message in their relevant Javadoc, to remind you of the risk of SQL injection in what is otherwise a SQL-injection-safe API.

    -
    +
    QueryParts - +

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

    @@ -6052,12 +5928,12 @@ create.fetch("SELECT * FROM BOOK WHERE ID = 5 AND TITLE = 'Animal Farm'");]]> The following sections explain some more details about and , as well as other implementation details about QueryParts in general.

    -
    +
    SQL rendering - +

    Every must implement the method to render its SQL string to a . This RenderContext has two purposes:

    @@ -6069,7 +5945,7 @@ create.fetch("SELECT * FROM BOOK WHERE ID = 5 AND TITLE = 'Animal Farm'");]]> API is given here:

    - +RenderContext castModeSome(SQLDialect... dialects);]]>

    The following additional methods are inherited from a common , which is shared among and :

    - +int peekIndex();]]>

    An example of rendering SQL

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

    --- [...] +-- [...] FROM AUTHOR JOIN BOOK ON AUTHOR.ID = BOOK.AUTHOR_ID --- [...] +-- [...]

    This is how jOOQ renders such a condition (simplified example):

    - +}]]>

    See the manual's sections about and to learn about how to write your own query parts in order to extend jOOQ.

    -
    +
    Pretty printing SQL - +

    As mentioned in the previous chapter about , there are some elements in the that are used for formatting / pretty-printing rendered SQL. In order to obtain pretty-printed SQL, just use the following :

    - +

    And then, use the above DSLContext to render pretty-printed SQL:

    - + - '1984' group by "TEST"."AUTHOR"."LAST_NAME" having count(*) = 2]]> - +

    The section about shows an example of how such pretty printing can be used to log readable SQL to the stdout.

    -
    +
    Variable binding - +

    Every must implement the method. This BindContext has two purposes:

    @@ -6212,7 +6087,7 @@ having count(*) = 2]]> An overview of the API is given here:

    - type) throws DataAccessException; -BindContext bindValues(Object... values) throws DataAccessException;]]> +BindContext bindValues(Object... values) throws DataAccessException;]]>

    Some additional methods are inherited from a common , which is shared among and . Details are documented in the previous chapter about @@ -6233,43 +6108,43 @@ BindContext bindValues(Object... values) throws DataAccessException;]]> A simple example can be provided by checking out jOOQ's internal representation of a (simplified) . It is used for any comparing two fields as for example the AUTHOR.ID = BOOK.AUTHOR_ID condition here:

    --- [...] +-- [...] WHERE AUTHOR.ID = ? --- [...] +-- [...]

    This is how jOOQ binds values on such a condition:

    - +}]]>

    See the manual's sections about and to learn about how to write your own query parts in order to extend jOOQ.

    -
    +
    Extend jOOQ with custom types - +

    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:

    - extends AbstractField {} + extends AbstractField {} public abstract class CustomCondition extends AbstractCondition {} public abstract class CustomTable> extends TableImpl {} -public abstract class CustomRecord> extends TableRecordImpl {}]]> +public abstract class CustomRecord> extends TableRecordImpl {}]]>

    These classes are declared public and covered by jOOQ's integration tests. When you extend these classes, you will have to provide your own implementations for the and methods, as discussed before:

    - +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. Here's an example showing how to create a field multiplying another field by 2

    - IDx2 = new CustomField(BOOK.ID.getName(), BOOK.ID.getDataType()) { @Override public void toSQL(RenderContext context) { @@ -6319,13 +6194,12 @@ final Field IDx2 = new CustomField(BOOK.ID.getName(), BOOK.ID. }; // Use the above field in a SQL statement: -create.select(IDx2).from(BOOK);]]> -
    +create.select(IDx2).from(BOOK);]]>
    Plain SQL QueryParts - +

    If you don't need the 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. Plain SQL methods in jOOQ's API come in two flavours.

    @@ -6337,29 +6211,29 @@ create.select(IDx2).from(BOOK);]]> The above distinction is best explained using an example:

    - id = val(5); Field title = val("Animal Farm"); -create.selectFrom(BOOK).where("BOOK.ID = {0} AND TITLE = {1}", id, title);]]> +create.selectFrom(BOOK).where("BOOK.ID = {0} AND TITLE = {1}", id, title);]]>

    The above technique allows for creating rather complex SQL clauses that are currently not supported by jOOQ, without extending any of the as indicated in the previous chapter.

    -
    +
    Serializability - +

    The only transient, non-serializable element in any jOOQ object is the underlying . When you want to execute queries after de-serialisation, or when you want to store/refresh/delete , you may have to "re-attach" them to a Configuration

    - select = (Select) in.readObject(); @@ -6368,20 +6242,20 @@ select.execute(); // In order to execute the above select, attach it first DSLContext create = DSL.using(connection, SQLDialect.ORACLE); -create.attach(select);]]> +create.attach(select);]]>

    Automatically attaching QueryParts

    Another way of attaching QueryParts automatically, or rather providing them with a new at will, is to hook into the . More details about this can be found in the manual's chapter about

    -
    +
    SQL building in Scala - +

    jOOQ-Scala is a maven module used for leveraging some advanced Scala features for those users that wish to use jOOQ with Scala.

    @@ -6394,7 +6268,7 @@ create.attach(select);]]> The following depicts a trait which wraps all fields:

    -(value : T) : Condition def <=>(value : Field[T]) : Condition -}]]> +}]]>

    The following depicts a trait which wraps numeric fields:

    ->(value : T) : Field[T] def >>(value : Field[T]) : Field[T] -}]]> +}]]>

    An example query using such overloaded operators would then look like this:

    - 2) or (T_BOOK.TITLE in ("O Alquimista", "Brida")) -fetch]]> +fetch]]>

    Scala 2.10 Macros

    This feature is still being experimented with. With Scala Macros, it might be possible to inline a true SQL dialect into the Scala syntax, backed by the jOOQ API. Stay tuned!

    -
    +
    SQL execution - +

    In a previous section of the manual, we've seen how jOOQ can be used to that can be executed with any API including JDBC or ... jOOQ. This section of the manual deals with various means of actually executing SQL with jOOQ.

    @@ -6541,12 +6415,12 @@ fetch]]>

    The following sections of this manual will show how jOOQ is wrapping JDBC for SQL execution

    -
    +
    Comparison between jOOQ and JDBC - +

    Similarities with JDBC

    Even if there are , there are a lot of similarities between JDBC and jOOQ. Just to name a few: @@ -6569,29 +6443,28 @@ fetch]]>

  • : JDBC keeps open resources even if they are already consumed. With JDBC, there is a lot of verbosity around safely closing resources. In jOOQ, resources are closed after consumption, by default. If you want to keep them open after consumption, you have to explicitly say so.
  • : JDBC execution flags and modes are not modified. They can be set fluently on a
  • -
    +
    Query vs. ResultQuery - +

    Unlike JDBC, jOOQ has a lot of knowledge about a SQL query's structure and internals (see the manual's section about ). Hence, jOOQ distinguishes between these two fundamental types of queries. While every can be executed, only can return results (see the manual's section about to learn more about fetching results). With plain SQL, the distinction can be made clear most easily:

    - resultQuery = create.resultQuery("SELECT * FROM BOOK"); -Result resultQuery.fetch();]]> -
    +Result resultQuery.fetch();]]>
    Fetching - +

    Fetching is something that has been completely neglegted by JDBC and also by various other database abstraction libraries. Fetching is much more than just looping or listing records or mapped objects. There are so many ways you may want to fetch data from a database, it should be considered a first-class feature of any database abstraction API. Just to name a few, here are some of jOOQ's fetching modes:

    @@ -6616,7 +6489,7 @@ Result resultQuery.fetch();]]> These modes of fetching are also documented in subsequent sections of the manual

    - fetch(); // The "standard" fetch when you know your query returns only one record @@ -6643,14 +6516,14 @@ List> fetchMany(); List fetch(RecordMapper mapper); // Execute a ResultQuery with jOOQ, but return a JDBC ResultSet, not a jOOQ object -ResultSet fetchResultSet();]]> +ResultSet fetchResultSet();]]>

    Fetch convenience

    These means of fetching are also available from and APIs

    - List fetch(Field field); List fetch(Field field, Class type); @@ -6684,14 +6557,14 @@ ResultSet fetchResultSet();]]> U fetchOne(int fieldIndex, Converter converter); Object fetchOne(String fieldName); T fetchOne(String fieldName, Class type); - U fetchOne(String fieldName, Converter converter);]]> + U fetchOne(String fieldName, Converter converter);]]>

    Fetch transformations

    These means of fetching are also available from and APIs

    - List fetchInto(Class type); // Transform your records into another table type - Result fetchInto(Table table);]]> + Result fetchInto(Table table);]]>

    Note, that apart from the methods, all fetch() methods will immediately close underlying JDBC result sets.

    -
    +
    Record vs. TableRecord - +

    jOOQ understands that SQL is much more expressive than Java, when it comes to the declarative typing of . As a declarative language, SQL allows for creating ad-hoc row value expressions (records with indexed columns, or tuples) and records (records with named columns). In Java, this is not possible to the same extent. Yet, still, sometimes you wish to use strongly typed records, when you know that you're selecting only from a single table

    @@ -6737,12 +6610,12 @@ ResultSet fetchResultSet();]]> When fetching data only from a single table, the type is known to jOOQ if you use jOOQ's to generate for your database tables. In order to fetch such strongly typed records, you will have to use the :

    - +System.out.println("Published in: " + book.getPublishedIn());]]>

    When you use the method, jOOQ will return the record type supplied with the argument table. Beware though, that you will no longer be able to use any clause that modifies the type of your . This includes: @@ -6751,17 +6624,17 @@ System.out.println("Published in: " + book.getPublishedIn());]]>

  • -
    +
    Record1 to Record{max-row-degree} - +

    jOOQ's support has been explained earlier in this manual. It is useful for constructing row value expressions where they can be used in SQL. The same typesafety is also applied to records for degrees up to {max-row-degree}. To express this fact, is extended by to . Apart from the fact that these extensions of the R type can be used throughout the , they also provide a useful API. Here is , for instance:

    - extends Record { + extends Record { // Access fields and values as row value expressions Row2 fieldsRow(); @@ -6774,23 +6647,23 @@ System.out.println("Published in: " + book.getPublishedIn());]]> // Access values by index T1 value1(); T2 value2(); -}]]> +}]]>

    Higher-degree records

    jOOQ chose to explicitly support degrees up to {max-row-degree} to match Scala's typesafe tuple, function and product support. Unlike Scala, however, jOOQ also supports higher degrees without the additional typesafety.

    -
    +
    Arrays, Maps and Lists - +

    By default, jOOQ returns an object, which is essentially a of . Often, you will find yourself wanting to transform this result object into a type that corresponds more to your specific needs. Or you just want to list all values of one specific column. Here are some examples to illustrate those use cases:

    - titles1 = create.select().from(BOOK).fetch().getValues(BOOK.TITLE); List titles2 = create.select().from(BOOK).fetch(BOOK.TITLE); String[] titles3 = create.select().from(BOOK).fetchArray(BOOK.TITLE); @@ -6810,22 +6683,22 @@ Map map4 = create.selectFrom(BOOK).fetchMap(BOOK.ID, BOOK.T Map> group1 = create.selectFrom(BOOK).fetch().intoGroups(BOOK.AUTHOR_ID); Map> group2 = create.selectFrom(BOOK).fetchGroups(BOOK.AUTHOR_ID); Map> group3 = create.selectFrom(BOOK).fetch().intoGroups(BOOK.AUTHOR_ID, BOOK.TITLE); -Map> group4 = create.selectFrom(BOOK).fetchGroups(BOOK.AUTHOR_ID, BOOK.TITLE);]]> +Map> group4 = create.selectFrom(BOOK).fetchGroups(BOOK.AUTHOR_ID, BOOK.TITLE);]]>

    Note that most of these convenience methods are available both through and , some are even available through as well.

    -
    +
    RecordHandler - +

    In a more functional operating mode, you might want to write callbacks that receive records from your select statement results in order to do some processing. This is a common data access pattern in Spring's JdbcTemplate, and it is also available in jOOQ. With jOOQ, you can implement your own classes and plug them into jOOQ's :

    - { Util.doThingsWithBook(book); }; ); -]]> +]]>

    See also the manual's section about the , which provides similar features

    -
    +
    RecordMapper - +

    In a more functional operating mode, you might want to write callbacks that map records from your select statement results in order to do some processing. This is a common data access pattern in Spring's JdbcTemplate, and it is also available in jOOQ. With jOOQ, you can implement your own classes and plug them into jOOQ's :

    - ids = create.selectFrom(BOOK) .orderBy(BOOK.ID) @@ -6881,7 +6754,7 @@ create.selectFrom(BOOK) create.selectFrom(BOOK) .orderBy(BOOK.ID) .fetch(book -> book.getId()); -]]> +]]>

    Your custom RecordMapper types can be used automatically through jOOQ's , by injecting a into your . @@ -6890,12 +6763,12 @@ create.selectFrom(BOOK)

    See also the manual's section about the , which provides similar features

    -
    +
    POJOs - +

    Fetching data in records is fine as long as your application is not really layered, or as long as you're still writing code in the DAO layer. But if you have a more advanced application architecture, you may not want to allow for jOOQ artefacts to leak into other layers. You may choose to write POJOs (Plain Old Java Objects) as your primary DTOs (Data Transfer Objects), without any dependencies on jOOQ's types, which may even potentially hold a reference to a , and thus a JDBC . Like Hibernate/JPA, jOOQ allows you to operate with POJOs. Unlike Hibernate/JPA, jOOQ does not "attach" those POJOs or create proxies with any magic in them.

    @@ -6908,7 +6781,7 @@ create.selectFrom(BOOK) jOOQ tries to find JPA annotations on your POJO types. If it finds any, they are used as the primary source for mapping meta-information. Only the annotation is used and understood by jOOQ. An example:

    - myBooks = create.select().from(BOOK).fetch().into(MyBook.class); -List myBooks = create.select().from(BOOK).fetchInto(MyBook.class);]]> +List myBooks = create.select().from(BOOK).fetchInto(MyBook.class);]]>

    Just as with any other JPA implementation, you can put the annotation on any class member, including attributes, setters and getters. Please refer to the Javadoc for more details. @@ -6931,7 +6804,7 @@ List myBooks = create.select().from(BOOK).fetchInto(MyBook.class);]]> - myBooks = create.select().from(BOOK).fetch().into(MyBook1.class); -List myBooks = create.select().from(BOOK).fetchInto(MyBook1.class);]]> +List myBooks = create.select().from(BOOK).fetchInto(MyBook1.class);]]>

    Please refer to the Javadoc for more details. @@ -6951,7 +6824,7 @@ List myBooks = create.select().from(BOOK).fetchInto(MyBook1.class);]]>< If jOOQ does not find any default constructor, columns are mapped to the "best-matching" constructor. This allows for using "immutable" POJOs with jOOQ. An example illustrates this:

    - myBooks = create.select(BOOK.ID, BOOK.AUTHOR_ID).from(BOOK).fetch().into(MyBook3.class); List myBooks = create.select(BOOK.ID, BOOK.AUTHOR_ID).from(BOOK).fetchInto(MyBook3.class); -]]> +]]>

    Please refer to the Javadoc for more details. @@ -6995,7 +6868,7 @@ List myBooks = create.select(BOOK.ID, BOOK.AUTHOR_ID).from(BOOK).fetchI jOOQ also allows for fetching data into abstract classes or interfaces, or in other words, "proxyable" types. This means that jOOQ will return a wrapped in a implementing your custom type. An example of this is given here:

    - myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetch().into(MyBook3.class); -List myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchInto(MyBook3.class);]]> +List myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchInto(MyBook3.class);]]>

    Please refer to the Javadoc for more details. @@ -7018,7 +6891,7 @@ List myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchInto( The above examples show how to fetch data into your own custom POJOs / DTOs. When you have modified the data contained in POJOs, you probably want to store those modifications back to the database. An example of this is given here:

    - +create.executeUpdate(book);]]>

    Note: Because of your manual setting of ID = 10, jOOQ's store() method will asume that you want to insert a new record. See the manual's section about for more details on this. @@ -7050,7 +6923,7 @@ create.executeUpdate(book);]]> If you're using jOOQ's , you can configure it to for you. Those DAOs operate on . An example of using such a DAO is given here:

    - +bookDao.delete(book);]]>

    More complex data structures

    jOOQ currently doesn't support more complex data structures, the way Hibernate/JPA attempt to map relational data onto POJOs. While future developments in this direction are not excluded, jOOQ claims that generic mapping strategies lead to an enormous additional complexity that only serves very few use cases. You are likely to find a solution using any of jOOQ's various , with only little boiler-plate code on the client side.

    -
    +
    POJOs with RecordMappers - +

    In the previous sections we have seen how to create types to map jOOQ records onto arbitrary objects. We have also seen how jOOQ provides default algorithms to map jOOQ records onto . Your own custom domain model might be much more complex, but you want to avoid looking up the most appropriate RecordMapper every time you need one. For this, you can provide jOOQ's with your own implementation of the interface. An example is given here:

    - )) .selectFrom(BOOK) .orderBy(BOOK.ID) - .fetchInto(UUID.class);]]> + .fetchInto(UUID.class);]]>

    The above is a very simple example showing that you will have complete flexibility in how to override jOOQ's record to POJO mapping mechanisms. @@ -7121,17 +6994,17 @@ bookDao.delete(book);]]>

    If you're looking into a generic, third-party mapping utility, have a look at ModelMapper, or Orika Mapper, which can both be easily integrated with jOOQ.

    -
    +
    Lazy fetching - +

    Unlike JDBC's , jOOQ's does not represent an open database cursor with various fetch modes and scroll modes, that needs to be closed after usage. jOOQ's results are simple in-memory Java objects, containing all of the result values. If your result sets are large, or if you have a lot of network latency, you may wish to fetch records one-by-one, or in small chunks. jOOQ supports a type for that purpose. In order to obtain such a reference, use the method. An example is given here:

    - cursor = null; try { @@ -7150,7 +7023,7 @@ finally { if (cursor != null) { cursor.close(); } -}]]> +}]]>

    As a holds an internal reference to an open , it may need to be closed at the end of iteration. If a cursor is completely scrolled through, it will conveniently close the underlying ResultSet. However, you should not rely on that. @@ -7166,16 +7039,16 @@ finally {

  • : You can use your own callbacks to map lazily fetched records.
  • : You can fetch data into your own custom POJO types.
  • -
    +
    Many fetching - +

    Many databases support returning several result sets, or cursors, from single queries. An example for this is Sybase ASE's sp_help command:

    - sp_help 'author' + sp_help 'author' +--------+-----+-----------+-------------+-------------------+ |Name |Owner|Object_type|Object_status|Create_date | @@ -7191,14 +7064,14 @@ finally { |last_name |varchar| 50|NULL| NULL| 0| |date_of_birth|date | 4|NULL| NULL| 1| |year_of_birth|int | 4|NULL| NULL| 1| -+-------------+-------+------+----+-----+-----+]]> ++-------------+-------+------+----+-----+-----+]]>

    The correct (and verbose) way to do this with JDBC is as follows:

    - +statement.close();]]>

    As previously discussed in the chapter about , jOOQ does not rely on an internal state of any JDBC object, which is "externalised" by Javadoc. Instead, it has a straight-forward API allowing you to do the above in a one-liner:

    -> results = create.fetchMany("sp_help 'author'");]]> +> results = create.fetchMany("sp_help 'author'");]]>

    Using generics, the resulting structure is immediately clear.

    -
    +
    Later fetching - +

    Some queries take very long to execute, yet they are not crucial for the continuation of the main program. For instance, you could be generating a complicated report in a Swing application, and while this report is being calculated in your database, you want to display a background progress bar, allowing the user to pursue some other work. This can be achived simply with jOOQ, by creating a , a type that extends . An example is given here:

    - future = create.selectFrom(BOOK).where(... complex predicates ...).fetchLater(); // This example actively waits for the result to be done @@ -7251,27 +7124,25 @@ while (!future.isDone()) { } // The result should be ready, now -Result result = future.get();]]> +Result result = future.get();]]>

    Note, that instead of letting jOOQ spawn a new thread, you can also provide jOOQ with your own :

    - future = create.selectFrom(BOOK).where(... complex predicates ...).fetchLater(service);]]> - -
    +FutureResult future = create.selectFrom(BOOK).where(... complex predicates ...).fetchLater(service);]]>
    ResultSet fetching - +

    When interacting with legacy applications, you may prefer to have jOOQ return a , rather than jOOQ's own types. This can be done simply, in two ways:

    - +rs2.close();]]>

    Transform jOOQ's Result into a JDBC ResultSet

    Instead of operating on a JDBC ResultSet holding an open resource from your database, you can also let jOOQ's wrap itself in a . The advantage of this is that the so-created ResultSet has no open connection to the database. It is a completely in-memory ResultSet:

    - result = create.selectFrom(BOOK).fetch(); -ResultSet rs = result.intoResultSet();]]> +ResultSet rs = result.intoResultSet();]]>

    The inverse: Fetch data from a legacy ResultSet using jOOQ

    The inverse of the above is possible too. Maybe, a legacy part of your application produces JDBC , and you want to turn them into a :

    - result = create.fetch(rs); // As a Cursor -Cursor cursor = create.fetchLazy(rs);]]> +Cursor cursor = create.fetchLazy(rs);]]>

    You can also tighten the interaction with jOOQ's data type system and features, by passing the record type to the above fetch methods:

    - result = create.fetch (rs, Integer.class, String.class); Cursor result = create.fetchLazy(rs, Integer.class, String.class); @@ -7318,22 +7189,22 @@ Cursor result = create.fetchLazy(rs, SQLDataType.INTEGER, SQLDataType.VA // Pass an array of fields: Result result = create.fetch (rs, BOOK.ID, BOOK.TITLE); -Cursor result = create.fetchLazy(rs, BOOK.ID, BOOK.TITLE);]]> +Cursor result = create.fetchLazy(rs, BOOK.ID, BOOK.TITLE);]]>

    If supplied, the additional information is used to override the information obtained from the 's

    -
    +
    Data type conversion - +

    Apart from a few extra features (), jOOQ only supports basic types as supported by the JDBC API. In your application, you may choose to transform these data types into your own ones, without writing too much boiler-plate code. This can be done using jOOQ's types. A converter essentially allows for two-way conversion between two Java data types <T> and <U>. By convention, the <T> type corresponds to the type in your database whereas the >U> type corresponds to your own user type. The Converter API is given here:

    - extends Serializable { + extends Serializable { /** * Convert a database object to a user object @@ -7354,7 +7225,7 @@ Cursor result = create.fetchLazy(rs, BOOK.ID, BOOK.TITLE);]]> * The user type */ Class toType(); -}]]> +}]]>

    Such a converter can be used in many parts of the jOOQ API. Some examples have been illustrated in the manual's section about . @@ -7365,7 +7236,7 @@ Cursor result = create.fetchLazy(rs, BOOK.ID, BOOK.TITLE);]]> Here is a some more elaborate example involving a Converter for :

    - { @Override @@ -7394,14 +7265,14 @@ public class CalendarConverter implements Converter dates1 = create.selectFrom(BOOK).fetch().getValues(BOOK.PUBLISHING_DATE, new CalendarConverter()); List dates2 = create.selectFrom(BOOK).fetch(BOOK.PUBLISHING_DATE, new CalendarConverter()); -]]> +]]>

    Enum Converters

    jOOQ ships with a built-in default , that you can use to map VARCHAR values to enum literals or NUMBER values to enum ordinals (both modes are supported). Let's say, you want to map a YES / NO / MAYBE column to a custom Enum:

    - +}]]>

    Using Converters in generated source code

    jOOQ also allows for generated source code to reference your own custom converters, in order to permanently replace a <T> type by your own, custom <U> type. See the manual's section about for details.

    -
    +
    Interning data - +

    SQL result tables are not optimal in terms of used memory as they are not designed to represent hierarchical data as produced by JOIN operations. Specifically, FOREIGN KEY values may repeat themselves unnecessarily:

    -+----+-----------+--------------+ ++----+-----------+--------------+ | ID | AUTHOR_ID | TITLE | +----+-----------+--------------+ | 1 | 1 | 1984 | | 2 | 1 | Animal Farm | | 3 | 2 | O Alquimista | | 4 | 2 | Brida | -+----+-----------+--------------+ ++----+-----------+--------------+

    Now, if you have millions of records with only few distinct values for AUTHOR_ID, you may not want to hold references to distinct (but equal) objects. This is specifically true for IDs of type or string representations thereof. jOOQ allows you to "intern" those values:

    - r1 = create.select(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE) .from(BOOK) .join(AUTHOR).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID)) @@ -7461,7 +7332,7 @@ Result r1 = create.select(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE) .from(BOOK) .join(AUTHOR).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID)) .intern(BOOK.AUTHOR_ID) - .fetch();]]> + .fetch();]]>

    You can specify as many fields as you want for interning. The above has the following effect: @@ -7479,14 +7350,14 @@ Result r1 = create.select(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE)

    Note, that jOOQ will not use interned data for identity comparisons: string1 == string2. Interning is used only to reduce the memory footprint of objects.

    -
    +
    Static statements vs. Prepared Statements - +

    With JDBC, you have full control over your SQL statements. You can decide yourself, if you want to execute a static without bind values, or a with (or without) bind values. But you have to decide early, which way to go. And you'll have to prevent SQL injection and syntax errors manually, when inlining your bind variables.

    @@ -7494,7 +7365,7 @@ Result r1 = create.select(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE) With jOOQ, this is easier. As a matter of fact, it is plain simple. With jOOQ, you can just set a flag in your , and all queries produced by that configuration will be executed as static statements, with all bind values inlined. An example is given here:

    - + r1 = create.select(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE) -- These statements are rendered by the two factories: SELECT ? FROM DUAL WHERE ? = ? -SELECT 1 FROM DUAL WHERE 1 = 1]]> - - +

    Reasons for choosing one or the other

    @@ -7528,12 +7398,12 @@ inlined.select(val(1)).where(val(1).equal(1)).fetch();]]>

    Note that you don't have to inline all your bind values at once. If you know that a bind value is not really a variable and should be inlined explicitly, you can do so by using , as documented in the manual's section about

    -
    +
    Reusing a Query's PreparedStatement - +

    As previously discussed in the chapter about , reusing PreparedStatements is handled a bit differently in jOOQ from how it is handled in JDBC

    @@ -7543,7 +7413,7 @@ inlined.select(val(1)).where(val(1).equal(1)).fetch();]]> With JDBC, you can easily reuse a by not closing it between subsequent executions. An example is given here:

    - +}]]>

    The above technique can be quite useful when you want to reuse expensive database resources. This can be the case when your statement is executed very frequently and your database would take non-negligible time to soft-parse the prepared statement and generate a new statement / cursor resource. @@ -7570,7 +7440,7 @@ finally { This is also modeled in jOOQ. However, the difference to JDBC is that closing a statement is the default action, whereas keeping it open has to be configured explicitly. This is better than JDBC, because the default action should be the one that is used most often. Keeping open statements is rarely done in average applications. Here's an example of how to keep open PreparedStatements with jOOQ:

    - query = create.selectOne().keepStatement(true); // Execute the query twice, against the same underlying PreparedStatement: @@ -7582,22 +7452,22 @@ try { // ... but now, you must not forget to close the query finally { query.close(); -}]]> +}]]>

    The above example shows how a query can be executed twice against the same underlying PreparedStatement. Unlike in other execution scenarios, you must not forget to close this query now

    -
    +
    JDBC flags - +

    JDBC knows a couple of execution flags and modes, which can be set through the jOOQ API as well. jOOQ essentially supports these flags and execution modes:

    - - - extends Query { +}]]> extends Query { // [...] @@ -7626,14 +7494,14 @@ finally { // ----------------------------------------------------------- ResultQuery maxRows(int rows); -}]]> +}]]>

    Using ResultSet concurrency with ExecuteListeners

    An example of why you might want to manually set a ResultSet's concurrency flag to something non-default is given here:

    - + .fetch(BOOK.TITLE);]]>

    In the above example, your custom is triggered before jOOQ loads a new Record from the JDBC ResultSet. With the concurrency being set to ResultSet.CONCUR_UPDATABLE, you can now modify the database cursor through the standard JDBC ResultSet API.

    -
    +
    Using JDBC batch operations - +

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

    @@ -7683,7 +7551,7 @@ DSL.using(new DefaultConfiguration()

    In code, this looks like the following snippet:

    - +int[] result = stmt.executeBatch();]]>

    This will also be supported by jOOQ

    @@ -7723,7 +7591,7 @@ int[] result = stmt.executeBatch();]]> jOOQ supports executing queries in batch mode as follows:

    - + .execute();]]>

    When creating a batch execution with a single query and multiple bind values, you will still have to provide jOOQ with dummy bind values for the original query. In the above example, these are set to null. For subsequent calls to bind(), there will be no type safety provided by jOOQ.

    -
    +
    Sequence execution - +

    Most databases support sequences of some sort, to provide you with unique values to be used for primary keys and other enumerations. If you're using jOOQ's , it will generate a sequence object per sequence for you. There are two ways of using such a sequence object:

    @@ -7759,34 +7627,34 @@ create.batch(create.insertInto(AUTHOR, ID, FIRST_NAME, LAST_NAME).values((Intege Instead of actually phrasing a select statement, you can also use the convenience methods:

    - +BigInteger currID = create.currval(S_AUTHOR_ID);]]>

    Inlining sequence references in SQL

    You can inline sequence references in jOOQ SQL statements. The following are examples of how to do that:

    - +]]>

    For more info about inlining sequence references in SQL statements, please refer to the manual's section about .

    -
    +
    Stored procedures and functions - +

    Many RDBMS support the concept of "routines", usually calling them procedures and/or functions. These concepts have been around in programming languages for a while, also outside of databases. Famous languages distinguishing procedures from functions are:

    @@ -7835,14 +7703,14 @@ create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) If you're using jOOQ's , it will generate objects for you. Let's consider the following example:

    - +

    The generated artefacts can then be used as follows:

    - +assertEquals(new BigDecimal("2"), procedure.getId();]]>

    But you can also call the procedure using a generated convenience method in a global Routines class:

    - +assertEquals(new BigDecimal("2"), procedure.getId();]]>

    For more details about for procedures, see the manual's section about . @@ -7874,31 +7742,30 @@ assertEquals(new BigDecimal("2"), procedure.getId();]]> Unlike procedures, functions can be inlined in SQL statements to generate or , if you're using . Assume you have a function like this:

    - +

    The generated artefacts can then be used as follows:

    - + - - +

    For more info about inlining stored function references in SQL statements, please refer to the manual's section about .

    -
    +
    Oracle Packages - +

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

    @@ -7912,17 +7779,17 @@ create.select(authorExists("Paulo")).fetchOne(0, boolean.class);]]>

    For more details about for procedures and packages see the manual's section about .

    -
    +
    Oracle member procedures - +

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

    - MEMBER FUNCTION counBOOKs RETURN NUMBER ) --- The type body is omitted for the example]]> +-- The type body is omitted for the example]]>

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

    - +assertNotNull(author.getLastName());]]>

    For more details about for UDTs see the manual's section about .

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

    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 the ). You can export any Result<Record> into the formats discussed in the subsequent chapters of the manual

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

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

    - + @@ -7994,86 +7859,79 @@ String xml = create.selectFrom(BOOK).fetch().formatXML(); Animal Farm -]]> +]]>

    The same result as an can be obtained using the Result.intoXML() method:

    -// Fetch books and format them as XML -Document xml = create.selectFrom(BOOK).fetch().intoXML(); +// Fetch books and format them as XML +Document xml = create.selectFrom(BOOK).fetch().intoXML();

    See the XSD schema definition here, for a formal definition of the XML export format:
    http://www.jooq.org/xsd/jooq-export-{export-xsd-version}.xsd

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

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

    -ID,AUTHOR_ID,TITLE +ID,AUTHOR_ID,TITLE 1,1,1984 -2,1,Animal Farm +2,1,Animal Farm

    In addition to the standard behaviour, you can also specify a separator character, as well as a special string to represent NULL values (which cannot be represented in standard CSV):

    -// Use ";" as the separator character +// Use ";" as the separator character String csv = create.selectFrom(BOOK).fetch().formatCSV(';'); // Specify "{null}" as a representation for NULL values -String csv = create.selectFrom(BOOK).fetch().formatCSV(';', "{null}"); - -
    +String csv = create.selectFrom(BOOK).fetch().formatCSV(';', "{null}");
    Exporting JSON - - -// Fetch books and format them as JSON -String json = create.selectFrom(BOOK).fetch().formatJSON(); + // Fetch books and format them as JSON +String json = create.selectFrom(BOOK).fetch().formatJSON();

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

    -{"fields":[{"name":"field-1","type":"type-1"}, +{"fields":[{"name":"field-1","type":"type-1"}, {"name":"field-2","type":"type-2"}, ..., {"name":"field-n","type":"type-n"}], "records":[[value-1-1,value-1-2,...,value-1-n], - [value-2-1,value-2-2,...,value-2-n]]} + [value-2-1,value-2-2,...,value-2-n]]}

    Note: This format has changed in jOOQ 2.6.0

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

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

    - + ID @@ -8093,76 +7951,72 @@ String html = create.selectFrom(BOOK).fetch().formatHTML(); Animal Farm -]]> - -
    +]]>
    Exporting Text - - -// Fetch books and format them as text -String text = create.selectFrom(BOOK).fetch().format(); + // Fetch books and format them as text +String text = create.selectFrom(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| -+---+---------+-----------+ ++---+---------+-----------+

    A simple text representation can also be obtained by calling toString() on a Result object. See also the manual's section about

    -
    +
    Importing data - +

    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 the formats described in the subsequent sections of this manual.

    -
    +
    Importing CSV - +

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

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

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

    -DSLContext create = DSL.using(connection, dialect); +DSLContext create = DSL.using(connection, dialect); // Load data into the AUTHOR table from an input stream // holding the CSV data. create.loadInto(AUTHOR) .loadCSV(inputstream) .fields(ID, AUTHOR_ID, TITLE) - .execute(); + .execute();

    Here are various other examples:

    -// Ignore the AUTHOR_ID column from the CSV file when inserting +// Ignore the AUTHOR_ID column from the CSV file when inserting create.loadInto(AUTHOR) .loadCSV(inputstream) .fields(ID, null, TITLE) @@ -8203,13 +8057,13 @@ create.loadInto(AUTHOR) .loadCSV(inputstream) .fields(ID, null, TITLE) - .execute(); + .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(); + loader = /* .. */ .execute(); // The number of processed rows int processed = loader.processed(); @@ -8232,23 +8086,21 @@ int rowIndex = error.rowIndex(); String[] row = error.row(); // The query that caused the error -Query query = error.query();]]> - -
    +Query query = error.query();]]>
    Importing XML - +

    This is not yet supported

    -
    +
    CRUD with UpdatableRecords - +

    Your database application probably consists of 50% - 80% CRUD, whereas only the remaining 20% - 50% of querying is actual querying. Most often, you will operate on records of tables without using any advanced relational concepts. This is called CRUD for

    @@ -8267,35 +8119,35 @@ Query query = error.query();]]> In normalised databases, every table has a primary key by which a tuple/record within that table can be uniquely identified. In simple cases, this is a (possibly auto-generated) number called ID. But in many cases, primary keys include several non-numeric columns. An important feature of such keys is the fact that in most databases, they are enforced using an index that allows for very fast random access to the table. A typical way to access / modify / delete a book is this:

    - +DELETE FROM BOOK WHERE ID = 5;]]>

    Normalised databases assume that a primary key is unique "forever", i.e. that a key, once inserted into a table, will never be changed or re-inserted after deletion. In order to use jOOQ's operations correctly, you should design your database accordingly.

    -
    +
    Simple CRUD - +

    If you're using jOOQ's , it will generate implementations for every table that has a primary key. When such a record form the database, these records are "attached" to the that created them. This means that they hold an internal reference to the same database connection that was used to fetch them. This connection is used internally by any of the following methods of the UpdatableRecord:

    - +int delete() throws DataAccessException;]]>

    See the manual's section about for some more insight on "attached" objects. @@ -8306,7 +8158,7 @@ int delete() throws DataAccessException;]]> Storing a record will perform an or an . In general, new records are always inserted, whereas records loaded from the database are always updated. This is best visualised in code:

    - +book2.store();]]>

    Some remarks about storing: @@ -8342,11 +8194,11 @@ book2.store();]]> Deleting a record will remove it from the database. Here's how you delete records:

    - +book.delete();]]>

    Refreshing

    @@ -8356,31 +8208,30 @@ book.delete();]]> In order to perform a refresh, use the following Java code:

    - +book.refresh();]]>

    CRUD and SELECT statements

    CRUD operations can be combined with regular querying, if you select records from single database tables, as explained in the manual's section about . For this, you will need to use the selectFrom() method from the :

    - -
    +}]]>
    Records' internal flags - +

    All of jOOQ's maintain an internal state for every column value. This state is composed of three elements:

    @@ -8393,34 +8244,34 @@ for (BookRecord book : create.fetch(BOOK, BOOK.PUBLISHED_IN.equal(1948))) {

    The purpose of the above information is for jOOQ's to know, which values need to be stored to the database, and which values have been left untouched.

    -
    +
    IDENTITY values - +

    Many databases support the concept of IDENTITY values, or key values. This is reflected by JDBC's method. jOOQ abstracts using this method as many databases and JDBC drivers behave differently with respect to generated keys. Let's assume the following SQL Server BOOK table:

    - +)]]>

    If you're using jOOQ's , the above table will generate a with an IDENTITY column. This information is used by jOOQ internally, to update IDs after calling :

    - +System.out.println(book.getId());]]>

    Database compatibility

    @@ -8429,8 +8280,8 @@ System.out.println(book.getId());]]>

    These SQL dialects implement the standard very neatly.

    - +

    H2, MySQL, Postgres, SQL Server, Sybase ASE, Sybase SQL Anywhere @@ -8438,7 +8289,7 @@ id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1)]]>

    These SQL dialects implement identites, but the DDL syntax doesn’t follow the standard

    - +id INTEGER NOT NULL IDENTITY]]>

    Oracle @@ -8462,7 +8313,7 @@ id INTEGER NOT NULL IDENTITY]]>

    Oracle does not know any identity columns at all. Instead, you will have to use a trigger and update the ID column yourself, using a custom sequence. Something along these lines:

    - +END my_trigger;]]>

    Note, that this approach can be employed in most databases supporting sequences and triggers! It is a lot more flexible than standard identities

    -
    +
    Non-updatable records - +

    Tables without a PRIMARY KEY are considered non-updatable by jOOQ, as jOOQ has no way of uniquely identifying such a record within the database. If you're using jOOQ's , such tables will generate classes, instead of classes. When you fetch from such a table, the returned records will not allow for calling any of the methods.

    @@ -8522,12 +8372,12 @@ List books = author.fetchChildren(FK_BOOK_AUTHOR);]]>

    Note, that some databases use internal rowid or object-id values to identify such records. jOOQ does not support these vendor-specific record meta-data.

    -
    +
    Optimistic locking - +

    jOOQ allows you to perform operations using optimistic locking. You can immediately take advantage of this feature by activating the relevant . Without any further knowledge of the underlying data semantics, this will have the following impact on store() and delete() methods:

    @@ -8542,7 +8392,7 @@ List books = author.fetchChildren(FK_BOOK_AUTHOR);]]> The above changes to jOOQ's behaviour are transparent to the API, the only thing you need to do for it to be activated is to set the Settings flag. Here is an example illustrating optimistic locking:

    - +book2.store();]]>

    Optimised optimistic locking using TIMESTAMP fields

    If you're using jOOQ's , you can take indicate TIMESTAMP or UPDATE COUNTER fields for every generated table in the . Let's say we have this table:

    - +)]]>

    The MODIFIED column will contain a timestamp indicating the last modification timestamp for any book in the BOOK table. If you're using jOOQ and it's , jOOQ will then generate this TIMESTAMP value for you, automatically. However, instead of running an additional statement prior to an UPDATE or DELETE statement, jOOQ adds a WHERE-clause to the UPDATE or DELETE statement, checking for TIMESTAMP's integrity. This can be best illustrated with an example:

    - +book2.store();]]>

    As before, without the added TIMESTAMP column, optimistic locking is transparent to the API. @@ -8605,17 +8455,17 @@ book2.store();]]>

    Note, for explicit pessimistic locking, please consider the manual's section about the . For more details about how to configure TIMESTAMP or VERSION fields, consider the manual's section about .

    -
    +
    Batch execution - +

    When inserting, updating, deleting a lot of records, you may wish to profit from JDBC batch operations, which can be performed by jOOQ. These are available through jOOQ's as shown in the following example:

    - books = create.fetch(BOOK); // Modify the above books, and add some new ones: @@ -8623,24 +8473,24 @@ modify(books); addMore(books); // Batch-update and/or insert all of the above books -create.batchStore(books);]]> +create.batchStore(books);]]>

    Internally, jOOQ will render all the required SQL statements and execute them as a regular .

    -
    +
    DAOs - +

    If you're using jOOQ's , you can configure it to generate and DAOs for you. jOOQ then generates one DAO per , i.e. per table with a single-column primary key. Generated DAOs implement a common jOOQ type called . This type contains the following methods:

    - corresponds to the DAO's related table + corresponds to the DAO's related table //

    corresponds to the DAO's related generated POJO type // corresponds to the DAO's related table's primary key type. // Note that multi-column primary keys are not yet supported by DAOs @@ -8676,13 +8526,13 @@ public interface DAO, P, T> { // These methods provide DAO meta-information Table getTable(); Class

    getType(); -}]]> +}]]>

    Besides these base methods, generated DAO classes implement various useful fetch methods. An incomplete example is given here, for the BOOK table:

    - { // Columns with primary / unique keys produce fetchOne() methods @@ -8691,12 +8541,12 @@ public class BookDao extends DAOImpl { // Other columns produce fetch() methods, returning several records public List fetchByAuthorId(Integer... values) { ... } public List fetchByTitle(String... values) { ... } -}]]> +}]]>

    Note that you can further subtype those pre-generated DAO classes, to add more useful DAO methods to them. Using such a DAO is simple:

    - - -
    +bookDao.delete(book);]]>
    Exception handling - +

    Checked vs. unchecked exceptions

    This is an eternal and religious debate. Pros and cons have been discussed time and again, and it still is a matter of taste, today. In this case, jOOQ clearly takes a side. jOOQ's exception strategy is simple: @@ -8751,12 +8599,12 @@ bookDao.delete(book);]]>

    The following section about documents means of overriding jOOQ's exception handling, if you wish to deal separately with some types of constraint violations, or if you raise business errors from your database, etc.

    -
    +
    ExecuteListeners - +

    The lets you specify a list of instances. 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, triggers, etc. Advanced ExecuteListeners can also provide custom implementations of Connection, PreparedStatement and ResultSet to jOOQ in apropriate methods.

    @@ -8767,7 +8615,7 @@ bookDao.delete(book);]]> Here is a sample implementation of an ExecuteListener, that is simply counting the number of queries per type that are being executed using jOOQ:

    - +}]]>

    Now, configure jOOQ's runtime to load your listener

    - +DSLContext create = DSL.using(configuration);]]>

    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 - 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 +15:16:52,983 INFO - OTHER : 30 executions

    Please read the for more details @@ -8831,7 +8679,7 @@ for (ExecuteType type : ExecuteType.values()) { The following depicts an example of a custom ExecuteListener, which pretty-prints all queries being executed by jOOQ to stdout:

    - +}]]>

    See also the manual's sections about and the for more sample implementations of actual ExecuteListeners.

    -
    +
    Database meta data - +

    Since jOOQ 3.0, a simple wrapping API has been added to wrap JDBC's rather awkward

    -
    +
    Logging - +

    jOOQ logs all SQL queries and fetched result sets to its internal DEBUG logger, which is implemented as an . By default, execute logging is activated in the . In order to see any DEBUG log output, put either log4j or slf4j on jOOQ's classpath along with their respective configuration. A sample log4j configuration can be seen here:

    - + @@ -8902,20 +8750,20 @@ public class PrettyPrinter extends DefaultExecuteListener { -]]> +]]>

    With the above configuration, let's fetch some data with jOOQ

    - +

    The above query may result in the following log output:

    - with bind values : select "BOOK"."ID", "BOOK"."TITLE" from "BOOK" order by "BOOK"."ID" asc, limit 2 offset 1 Query executed : Total: 1.439ms Fetched result : +----+------------+ @@ -8925,7 +8773,7 @@ Fetched result : +----+------------+ : | 3|O Alquimista| : +----+------------+ Finishing : Total: 4.814ms, +3.375ms -]]> +]]>

    Essentially, jOOQ will log @@ -8941,12 +8789,12 @@ Finishing : Total: 4.814ms, +3.375ms

    If you wish to use your own logger (e.g. avoiding printing out sensitive data), you can deactivate jOOQ's logger using and implement your own .

    -
    +
    Performance considerations - +

    Many users may have switched from higher-level abstractions such as Hibernate to jOOQ, because of Hibernate's difficult-to-manage performance, when it comes to large database schemas and complex second-level caching strategies. However, jOOQ itself is not a lightweight database abstraction framework, and it comes with its own overhead. Please be sure to consider the following points:

    @@ -8961,14 +8809,14 @@ Finishing : Total: 4.814ms, +3.375ms

    Don't be put off by the above paragraphs. You should optimise wisely, i.e. only in places where you really need very high throughput to your database. jOOQ's overhead compared to plain JDBC is typically less than 1ms per query.

    -
    +
    Code generation - +

    While optional, source code generation is one of jOOQ's main assets if you wish to increase developer productivity. jOOQ's code generator takes your database schema and reverse-engineers it into a set of Java classes modelling , , , , , , user-defined types and many more.

    @@ -8982,12 +8830,12 @@ Finishing : Total: 4.814ms, +3.375ms

    The following chapters will show how to configure the code generator and how to generate various artefacts.

    -
    +
    Configuration and setup of the generator - +

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

    @@ -9014,7 +8862,7 @@ Finishing : Total: 4.814ms, +3.375ms You need to tell jOOQ some things about your database connection. Here's an example of how to do it for an Oracle database

    - + @@ -9088,7 +8936,7 @@ Finishing : Total: 4.814ms, +3.375ms [/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 for a formal specification at:
    @@ -9100,7 +8948,7 @@ Finishing : Total: 4.814ms, +3.375ms Code generation works by calling this class with the above property file as argument.

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

    Be sure that these elements are located on the classpath: @@ -9168,20 +9016,20 @@ Finishing : Total: 4.814ms, +3.375ms 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 @@ -9233,7 +9081,7 @@ Finishing : Total: 4.814ms, +3.375ms -]]> +]]>

    See the full example of a pom.xml including the jOOQ-codegen artefact here:
    @@ -9245,17 +9093,17 @@ Finishing : Total: 4.814ms, +3.375ms

    Be sure, both jooq-{jooq-version}.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.

    -
    +
    Advanced generator configuration - +

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

    - + @@ -9267,13 +9115,13 @@ Finishing : Total: 4.814ms, +3.375ms org.jooq.util.DefaultGeneratorStrategy -]]> +]]>

    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:

    - +}]]>

    More examples can be found here: @@ -9394,7 +9242,7 @@ public class AsInDatabaseStrategy extends DefaultGeneratorStrategy { Within the <generator/> element, there are other configuration elements:

    - + ... -]]> +]]>

    Check out the some of the manual's "advanced" sections to find out more about the advanced configuration parameters. @@ -9456,7 +9304,7 @@ public class AsInDatabaseStrategy extends DefaultGeneratorStrategy { Also, you can add some optional advanced configuration parameters for the generator:

    - + true -]]> +]]>

    Property interdependencies

    @@ -9537,12 +9385,12 @@ public class AsInDatabaseStrategy extends DefaultGeneratorStrategy {

  • When daos = true, then jOOQ will set pojos = true
  • When immutablePojos = true, then jOOQ will set pojos = true
  • -
    +
    Generated global artefacts - +

    For increased convenience at the use-site, jOOQ generates "global" artefacts at the code generation root location, referencing tables, routines, sequences, etc. In detail, these global artefacts include the following:

    @@ -9559,7 +9407,7 @@ public class AsInDatabaseStrategy extends DefaultGeneratorStrategy { When referencing global artefacts from your client application, you would typically static import them as such:

    - -
    + .values(com.example.generated.Sequences.MY_SEQUENCE.nextval(), com.example.generated.Routines.myFunction())]]>
    Generated tables - +

    Every table in your database will generate a implementation that looks like this:

    - { + { // The singleton instance public static final Book BOOK = new Book(); @@ -9598,7 +9445,7 @@ create.insertInto(com.example.generated.Tables.MY_TABLE) } // [...] -}]]> +}]]>

    Flags influencing generated tables

    @@ -9618,17 +9465,17 @@ create.insertInto(com.example.generated.Tables.MY_TABLE)

    Table generation cannot be deactivated

    -
    +
    Generated records - +

    Every table in your database will generate a implementation that looks like this:

    - @@ -9669,7 +9516,7 @@ implements IBook { } // [...] -}]]> +}]]>

    Flags influencing generated records

    @@ -9689,17 +9536,17 @@ implements IBook {

    Record generation can be deactivated using the records flag

    -
    +
    Generated POJOs - +

    Every table in your database will generate a POJO implementation that looks like this:

    - +}]]>

    Flags influencing generated POJOs

    @@ -9752,24 +9599,24 @@ public class Book implements java.io.Serializable

    POJO generation can be activated using the pojos flag

    -
    +
    Generated Interfaces - +

    Every table in your database will generate an interface that looks like this:

    - +}]]>

    Flags influencing generated interfaces

    @@ -9784,18 +9631,18 @@ public class Book implements java.io.Serializable

    POJO generation can be activated using the interfaces flag

    -
    +
    Generated DAOs - +

    Generated DAOs

    Every table in your database will generate a implementation that looks like this:

    - { + { // Generated constructors public BookDao() { @@ -9820,43 +9667,43 @@ public class Book implements java.io.Serializable } // [...] -}]]> +}]]>

    Flags controlling DAO generation

    DAO generation can be activated using the daos flag

    -
    +
    Generated sequences - +

    Every sequence in your database will generate a implementation that looks like this:

    - S_AUTHOR_ID = new SequenceImpl("S_AUTHOR_ID", TEST, SQLDataType.INTEGER); -}]]> +}]]>

    Flags controlling sequence generation

    Sequence generation cannot be deactivated

    -
    +
    Generated procedures - +

    Every procedure or function (routine) in your database will generate a implementation that looks like this:

    - { + { // All IN, IN OUT, OUT parameters and function return values generate a static member public static final Parameter AUTHOR_NAME = createParameter("AUTHOR_NAME", SQLDataType.VARCHAR); @@ -9881,7 +9728,7 @@ public class Book implements java.io.Serializable } // [...] -}]]> +}]]>

    Package and member procedures or functions

    @@ -9892,17 +9739,17 @@ public class Book implements java.io.Serializable

    Routine generation cannot be deactivated

    -
    +
    Generated UDTs - +

    Every UDT in your database will generate a implementation that looks like this:

    - { + { // The singleton UDT instance public static final UAddressType U_ADDRESS_TYPE = new UAddressType(); @@ -9916,13 +9763,13 @@ public class Book implements java.io.Serializable createField("COUNTRY", SQLDataType.VARCHAR, U_ADDRESS_TYPE); // [...] -}]]> +}]]>

    Besides the implementation, a implementation is also generated

    - { + { // Every attribute generates a getter and a setter @@ -9934,25 +9781,25 @@ public class Book implements java.io.Serializable public String getCountry() {...} // [...] -}]]> +}]]>

    Flags controlling UDT generation

    UDT generation cannot be deactivated

    -
    +
    Data type rewrites - +

    Sometimes, the actual database data type does not match the SQL data type that you would like to use in Java. This is often the case for ill-supported SQL data types, such as BOOLEAN or UUID. jOOQ's code generator allows you to apply simple data type rewriting. The following configuration will rewrite IS_VALID columns in all tables to be of type BOOLEAN.

    - + @@ -9965,23 +9812,23 @@ public class Book implements java.io.Serializable .*\.IS_VALID -]]> +]]>

    See the section about for rewriting columns to your own custom data types.

    -
    +
    Custom data types and type conversion - +

    When using a custom type in jOOQ, you need to let jOOQ know about its associated . Ad-hoc usages of such converters has been discussed in the chapter about . 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_

    - + @@ -10005,41 +9852,39 @@ public class Book implements java.io.Serializable .*\.DATE_OF_.* -]]> +]]>

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

    - { + { // [...] public final TableField DATE_OF_BIRTH = // [...] // [...] -}]]> +}]]>

    This means that the bound type 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(AUTHOR) .where(AUTHOR.DATE_OF_BIRTH.greaterThan(new GregorianCalendar(1980, 0, 1))) - .fetch(AUTHOR.DATE_OF_BIRTH);]]> - -
    + .fetch(AUTHOR.DATE_OF_BIRTH);]]>
    Mapping generated schemata and tables - +

    We've seen previously in the chapter about , that schemata and tables can be mapped at runtime to other names. But 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 @@ -10047,14 +9892,12 @@ create.selectFrom(AUTHOR) PROD -]]> - -
    +]]>
    Code generation for large schemas - +

    Databases can become very large in real-world applications. This is not a problem for jOOQ's code generator, but it can be for the Java compiler. jOOQ generates some classes for . These classes can hit two sorts of limits of the compiler / JVM:

    @@ -10074,23 +9917,23 @@ create.selectFrom(AUTHOR)
  • to avoid generating using <globalObjectReferences/>
  • Remove uncompilable classes after code generation
  • -
    +
    Tools - +

    These chapters hold some information about tools to be used with jOOQ

    -
    +
    JDBC mocking for unit testing - +

    When writing unit tests for your data access layer, you have probably used some generic mocking tool offered by popular providers like Mockito, jmock, mockrunner, or even DBUnit. With jOOQ, you can take advantage of the built-in JDBC mock API that allows you to simulate a database on the JDBC level for precisely those SQL/JDBC use cases supported by jOOQ.

    @@ -10117,7 +9960,7 @@ create.selectFrom(AUTHOR) This work is greatly simplified, when using jOOQ's own mock API. The org.jooq.tools.jdbc package contains all the essential implementations for both JDBC 4.0 and 4.1, which are needed to mock JDBC for jOOQ. In order to write mock tests, provide the jOOQ with a , and implement the :

    - result = create.selectFrom(BOOK).where(BOOK.ID.equal(5)).fetch();]]> +Result result = create.selectFrom(BOOK).where(BOOK.ID.equal(5)).fetch();]]>

    As you can see, the configuration setup is simple. Now, the MockDataProvider acts as your single point of contact with JDBC / jOOQ. It unifies any of these execution modes, transparently: @@ -10149,7 +9992,7 @@ Result result = create.selectFrom(BOOK).where(BOOK.ID.equal(5)).fetc Now, here's how to implement MockDataProvider:

    - result = create.selectFrom(BOOK).where(BOOK.ID.equal(5)).fetc return mock; } -}]]> +}]]>

    Essentially, the contains all the necessary information for you to decide, what kind of data you should return. The wraps up two pieces of information: @@ -10201,12 +10044,12 @@ Result result = create.selectFrom(BOOK).where(BOOK.ID.equal(5)).fetc

    See the for a list of rules that you should follow.

    -
    +
    jOOQ Console - +

    The 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:

    @@ -10246,19 +10089,19 @@ Result result = create.selectFrom(BOOK).where(BOOK.ID.equal(5)).fetc Both modes will require that you set the in the Configuration:

    - +DSLContext create = DSL.using(configuration);]]>

    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: @@ -10319,36 +10162,36 @@ catch (Exception ignore) {} 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 +// Create a new RemoteDebuggerServer in your application that listens to // incoming connections on a given port -SERVER = new RemoteDebuggerServer(DEBUGGER_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-{jooq-version}.jar [host] [port] +java -jar jooq-console-{jooq-version}.jar [host] [port]

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

    -
    +
    Reference - +

    These chapters hold some general jOOQ reference information

    -
    +
    Supported RDBMS - +

    A list of supported databases

    Every RDMBS out there has its own little specialties. jOOQ considers those specialties as much as possible, while trying to standardise the behaviour in jOOQ. In order to increase the quality of jOOQ, some 70 unit tests are run for syntax and variable binding verification, as well as some 180 integration tests with an overall of around 1200 queries for any of these databases: @@ -10407,12 +10250,12 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);

    This section will soon contain a feature matrix, documenting what feature is available for which database.

    -
    +
    Data types - +

    There is always a small mismatch between SQL data types and Java data types. This is for two reasons:

    @@ -10423,21 +10266,21 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);

    This chapter should document the most important notes about SQL, JDBC and jOOQ data types.

    -
    +
    BLOBs and CLOBs - +

    jOOQ currently doesn't explicitly support JDBC BLOB and CLOB data types. If you use any of these data types in your database, jOOQ will map them to byte[] and String instead. In simple cases (small data), this simplification is sufficient. In more sophisticated cases, you may have to bypass jOOQ, in order to deal with these data types and their respective resources. True support for LOBs is on the roadmap, though.

    -
    +
    Unsigned integer types - +

    Some databases explicitly support unsigned integer data types. In most normal JDBC-based applications, they would just be mapped to their signed counterparts letting bit-wise shifting and tweaking to the user. jOOQ ships with a set of unsigned implementations modelling the following types:

    @@ -10456,12 +10299,12 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);
  • UInteger wraps
  • ULong wraps
  • -
    +
    INTERVAL data types - +

    jOOQ fills a gap opened by JDBC, which neglects an important SQL data type as defined by the SQL standards: INTERVAL types. SQL knows two different types of intervals:

    @@ -10486,51 +10329,51 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);
  • INTERVAL * or / NUMERIC => INTERVAL
  • NUMERIC * INTERVAL => INTERVAL
  • -
    +
    XML data types - +

    XML data types are currently not supported

    -
    +
    Geospacial data types - +

    Geospacial data types

    Geospacial data types are currently not supported

    -
    +
    CURSOR data types - +

    Some databases support cursors returned from stored procedures. They are mapped to the following jOOQ data type:

    -> cursor;]]> +> cursor;]]>

    In fact, such a cursor will be fetched immediately by jOOQ and wrapped in an object.

    -
    +
    ARRAY and TABLE data types - +

    The SQL standard specifies ARRAY data types, that can be mapped to Java arrays as such:

    - intArray;]]> + intArray;]]>

    The above array type is supported by these SQL dialects: @@ -10545,14 +10388,14 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT);

    Oracle has strongly-typed arrays and table types (as opposed to the previously seen anonymously typed arrays). These arrays are wrapped by types.

    -
    +
    SQL to DSL mapping rules - +

    jOOQ takes SQL as an external domain-specific language and maps it onto Java, creating an internal domain-specific language. Internal DSLs cannot 100% implement their external language counter parts, as they have to adhere to the syntax rules of their host or target language (i.e. Java). This section explains the various problems and workarounds encountered and implemented in jOOQ.

    @@ -10562,19 +10405,17 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT); SQL syntax does not always need keywords to form expressions. The clause takes various argument assignments:

    - -UPDATE t SET a = 1, b = 2 -update(t).set(a, 1).set(b, 2) - + +UPDATE t SET a = 1, b = 2update(t).set(a, 1).set(b, 2) +

    The above example also shows missing operator overloading capabilities, where "=" is replaced by "," in jOOQ. Another example are , which can be formed with parentheses only in SQL:

    - -(a, b) IN ((1, 2), (3, 4)) -row(a, b).in(row(1, 2), row(3, 4)) - + +(a, b) IN ((1, 2), (3, 4))row(a, b).in(row(1, 2), row(3, 4)) +

    In this case, ROW is an actual (optional) SQL keyword, implemented by at least PostgreSQL. @@ -10585,27 +10426,25 @@ SERVER = new RemoteDebuggerServer(DEBUGGER_PORT); As most languages, SQL does not attribute any meaning to whitespace. However, whitespace is important when forming "composed" keywords, i.e. SQL clauses composed of several keywords. jOOQ follows standard Java method naming conventions to map SQL keywords (case-insensitive) to Java methods (case-sensitive, camel-cased). Some examples:

    - + GROUP BY ORDER BY -WHEN MATCHED THEN UPDATE -groupBy() +WHEN MATCHED THEN UPDATEgroupBy() orderBy() whenMatchedThenUpdate() - +

    Future versions of jOOQ may use all-uppercased method names in addition to the camel-cased ones (to prevent collisions with Java keywords):

    - + GROUP BY ORDER BY -WHEN MATCHED THEN UPDATE -GROUP_BY() +WHEN MATCHED THEN UPDATEGROUP_BY() ORDER_BY() WHEN_MATCHED_THEN_UPDATE() - +

    SQL contains "superfluous" keywords

    @@ -10620,10 +10459,9 @@ WHEN_MATCHED_THEN_UPDATE() jOOQ omits some of those keywords when it is too tedious to write them in Java.

    - -CASE WHEN .. THEN .. END -decode().when(.., ..) - + +CASE WHEN .. THEN .. ENDdecode().when(.., ..) +

    The above example omits THEN and END keywords in Java. Future versions of jOOQ may comprise a more complete DSL, including such keywords again though, to provide a more 1:1 match for the SQL language. @@ -10634,23 +10472,21 @@ WHEN_MATCHED_THEN_UPDATE() Some SQL constructs are hard to map to Java, but they are also not really necessary. SQL often expects syntactic parentheses where they wouldn't really be needed, or where they feel slightly inconsistent with the rest of the SQL language.

    - + LISTAGG(a, b) WITHIN GROUP (ORDER BY c) - OVER (PARTITION BY d) -listagg(a, b).withinGroupOrderBy(c) + OVER (PARTITION BY d)listagg(a, b).withinGroupOrderBy(c) .over().partitionBy(d) - +

    The parentheses used for the WITHIN GROUP (..) and OVER (..) clauses are required in SQL but do not seem to add any immediate value. In some cases, jOOQ omits them, although the above might be optionally re-phrased in the future to form a more SQLesque experience:

    - + LISTAGG(a, b) WITHIN GROUP (ORDER BY c) - OVER (PARTITION BY d) -listagg(a, b).withinGroup(orderBy(c)) + OVER (PARTITION BY d)listagg(a, b).withinGroup(orderBy(c)) .over(partitionBy(d)) - +

    SQL uses some of Java's reserved words

    @@ -10666,12 +10502,11 @@ WHEN_MATCHED_THEN_UPDATE() jOOQ replaces those keywords by "synonyms":

    - + CASE .. ELSE -PIVOT .. FOR .. IN .. -decode() .. otherwise() +PIVOT .. FOR .. IN ..decode() .. otherwise() pivot(..).on(..).in(..) - +

    There is more future collision potential with: @@ -10694,70 +10529,67 @@ pivot(..).on(..).in(..) Most SQL operators have to be mapped to descriptive method names in Java, as Java does not allow operator overloading:

    - + , != || -SET a = b]]> -equal(), eq() +SET a = b]]>equal(), eq() notEqual(), ne() concat() set(a, b) - +

    For those users using , operator overloading and implicit conversion can be leveraged to enhance jOOQ:

    - + , != -||]]> -, !== ||]]> - +

    SQL's reference before declaration capability

    This is less of a syntactic SQL feature than a semantic one. In SQL, objects can be referenced before (i.e. "lexicographically before") they are declared. This is particularly true for

    - + - - +

    A more sophisticated example are common table expressions (CTE), which are currently not supported by jOOQ:

    -WITH t(a, b) AS ( +WITH t(a, b) AS ( SELECT 1, 2 FROM DUAL ) SELECT t.a, t.b -FROM t +FROM t

    Common table expressions define a "derived column list", just like can do. The formal record type thus created cannot be typesafely verified by the Java compiler, i.e. it is not possible to formally dereference t.a from t.

    -
    +
    jOOQ's BNF pseudo-notation - +

    This chapter will soon contain an overview over jOOQ's API using a pseudo BNF notation.

    -
    +
    Quality Assurance - +

    jOOQ is running some of your most mission-critical logic: the interface layer between your Java / Scala application and the database. You have probably chosen jOOQ for any of the following reasons:

    @@ -10797,7 +10629,7 @@ FROM t jOOQ is used in jOOQ-meta as a proof of concept. This includes complex queries such as the following Postgres query

    - +}]]>

    These rather complex queries show that the jOOQ API is fit for advanced SQL use-cases, compared to the rather simple, often unrealistic queries in the integration test suite.

    @@ -10860,12 +10692,12 @@ for (Record record : create().select(

    Keeping things DRY leads to longer stack traces, but in turn, also increases the relevance of highly reusable code-blocks. Chances that some parts of the jOOQ code base slips by integration test coverage decrease significantly.

    -
    +
    Migrating to jOOQ 3.0 - +

    This section is for all users of jOOQ 2.x who wish to upgrade to the next major release. In the next sub-sections, the most important changes are explained. Some code hints are also added to help you fix compilation errors.

    @@ -10889,13 +10721,13 @@ for (Record record : create().select( Some hints related to row value expressions:

    - record = create.select(BOOK.TITLE, BOOK.ID).from(BOOK).where(ID.eq(1)).fetchOne(); Result> result = create.select(BOOK.TITLE, BOOK.ID).from(BOOK).fetch(); // But Record2 extends Record. You don't have to use the additional typesafety: Record record = create.select(BOOK.TITLE, BOOK.ID).from(BOOK).where(ID.eq(1)).fetchOne(); -Result result = create.select(BOOK.TITLE, BOOK.ID).from(BOOK).fetch();]]> +Result result = create.select(BOOK.TITLE, BOOK.ID).from(BOOK).fetch();]]>

    SelectQuery and SelectXXXStep are now generic

    @@ -10921,7 +10753,7 @@ Result result = create.select(BOOK.TITLE, BOOK.ID).from(BOOK).fetch();]]> - + ).fetch(); // Execute the "attached" query]]>

    Quantified comparison predicates

    Field.equalAny(...) and similar methods have been removed in favour of Field.equal(any(...)). This greatly simplified the Field API. An example:

    -> subselect = any(select(BOOK.ID).from(BOOK)); -Condition condition = BOOK.ID.equal(subselect);]]> +Condition condition = BOOK.ID.equal(subselect);]]>

    FieldProvider

    @@ -10957,7 +10789,7 @@ Condition condition = BOOK.ID.equal(subselect);]]> GroupField has been introduced as a DSL marker interface to denote fields that can be passed to GROUP BY clauses. This includes all org.jooq.Field types. However, fields obtained from ROLLUP(), CUBE(), and GROUPING SETS() functions no longer implement Field. Instead, they only implement GroupField. An example:

    - field1a = Factory.rollup(...); // OK Field field2a = Factory.one(); // OK @@ -10965,7 +10797,7 @@ Field field2a = Factory.one(); // OK GroupField field1b = DSL.rollup(...); // OK Field field1c = DSL.rollup(...); // Compilation error GroupField field2b = DSL.one(); // OK -Field field2c = DSL.one(); // OK]]> +Field field2c = DSL.one(); // OK]]>

    NULL predicate

    @@ -10983,14 +10815,14 @@ Field field2c = DSL.one(); // OK]]> Here is an example how to check if a field has a given value, without applying SQL's ternary NULL logic:

    - +Condition condition3 = BOOK.TITLE.isNotDistinctFrom(possiblyNull);]]>

    Configuration

    @@ -11011,14 +10843,14 @@ Condition condition3 = BOOK.TITLE.isNotDistinctFrom(possiblyNull);]]> In order to allow for simpler connection / data source management, jOOQ externalised connection handling in a new ConnectionProvider type. The previous two connection modes are maintained backwards-compatibly (JDBC standalone connection mode, pooled DataSource mode). Other connection modes can be injected using:

    - +}]]>

    These are some side-effects of the above change @@ -11068,7 +10900,7 @@ Condition condition3 = BOOK.TITLE.isNotDistinctFrom(possiblyNull);]]>

  • The UpdatableTable type has been removed. While adding significant complexity to the type hierarchy, this type adds not much value over a simple Table.getPrimaryKey() != null check.
  • The USE statement support has been removed from jOOQ. Its behaviour was ill-defined, while it didn't work the same way (or didn't work at all) in some databases.
  • -
    +
    @@ -1616,7 +1605,7 @@ public void bind(BindContext context) throws DataAccessException; [/path/to/your/dir] -]]> +]]>

    There are also lots of advanced configuration parameters, which will be @@ -1627,7 +1616,7 @@ public void bind(BindContext context) throws DataAccessException;

    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 + org.jooq.util.GenerationTool /jooq-config.xml

    Be sure that these elements are located on the classpath:

    • The property file
    • @@ -1681,7 +1670,7 @@ public void bind(BindContext context) throws DataAccessException; remove the dots "." and dashes "-" from the .properties file's property names to get the ant task's arguments:

      - + @@ -1704,25 +1693,25 @@ public void bind(BindContext context) throws DataAccessException; generatordatabaseinputschema="test" generatortargetpackage="org.jooq.test.generatedclasses" generatortargetdirectory="${basedir}/src"/> -]]> +]]>

      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 @@ -1778,7 +1767,7 @@ public void bind(BindContext context) throws DataAccessException; -]]> +]]>

      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

      @@ -1790,7 +1779,7 @@ public void bind(BindContext context) throws DataAccessException; 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 + 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 @@ -1800,13 +1789,13 @@ public void bind(BindContext context) throws DataAccessException;

      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.

      - +
    Advanced generator configuration - +

    Code generation

    In the @@ -1815,7 +1804,7 @@ public void bind(BindContext context) throws DataAccessException; settings

    - + @@ -1827,7 +1816,7 @@ public void bind(BindContext context) throws DataAccessException; org.jooq.util.DefaultGeneratorStrategy -]]> +]]>

    The following example shows how you can override the @@ -1836,7 +1825,7 @@ public void bind(BindContext context) throws DataAccessException; camel case:

    - +}]]>

    jooq-meta configuration

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

    - + ... -]]> +]]>

    Check out the some of the manual's "advanced" sections @@ -2003,7 +1992,7 @@ public class AsInDatabaseStrategy extends DefaultGeneratorStrategy {

    jooq-codegen configuration

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

    - + false -]]> -
    +]]>
    The schema, top-level generated artefact - +

    The Schema

    As of jOOQ 1.5, the top-level generated object is the @@ -2094,15 +2082,14 @@ public class AsInDatabaseStrategy extends DefaultGeneratorStrategy {

    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(); -
    +public final java.util.List<org.jooq.Sequence<?>> getSequences(); +public final java.util.List<org.jooq.Table<?>> getTables();
    Tables, views and their records - +

    Tables and TableRecords

    The most important generated artefacts are @@ -2125,7 +2112,7 @@ public final java.util.List<org.jooq.Table<?>> getTables();

    The Table as an entity meta model

    -public class TAuthor extends UpdatableTableImpl<TAuthorRecord> { +public class TAuthor extends UpdatableTableImpl<TAuthorRecord> { // The singleton instance of the Table public static final TAuthor T_AUTHOR = new TAuthor(); @@ -2143,7 +2130,7 @@ public final java.util.List<org.jooq.Table<?>> getTables(); public TAuthor as(String alias) { // [...] } -} +}

    The Table's associated TableRecord

    If you use the @@ -2153,7 +2140,7 @@ public final java.util.List<org.jooq.Table<?>> getTables(); extends Record>'s associated Record type <R>. In the case of the above TAuthor Table, this will be a TAuthorRecord.

    -public class TAuthorRecord extends UpdatableRecordImpl<TAuthorRecord> { +public class TAuthorRecord extends UpdatableRecordImpl<TAuthorRecord> { // Getters and setters for the various fields public void setId(Integer value) { // [...] @@ -2167,7 +2154,7 @@ public final java.util.List<org.jooq.Table<?>> getTables(); // Navigation methods for foreign keys public List<TBookRecord> fetchTBooks() { // [...] -} +}

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

    @@ -2178,7 +2165,7 @@ public final java.util.List<org.jooq.Table<?>> getTables(); POJOs. Let's say you defined a POJO for authors:

    - +}]]>

    The above could be your custom POJO or a POJO generated @@ -2222,20 +2209,20 @@ public class MyAuthor { you can now let jOOQ fetch records "into" your custom type:

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

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

    -
    +
    Procedures and packages - +

    Stored procedures in modern RDBMS

    This is one of the most important reasons why you should consider jOOQ. Read also my @@ -2254,14 +2241,14 @@ public class MyAuthor {

    "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 +-- Check whether there is an author in T_AUTHOR by that name CREATE OR REPLACE FUNCTION f_author_exists (author_name VARCHAR2) RETURN NUMBER; -- 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); -- 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); +CREATE OR REPLACE PROCEDURE p_author_exists_2 (author_name VARCHAR2, result OUT NUMBER, id OUT NUMBER);

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

      @@ -2270,7 +2257,7 @@ CREATE OR REPLACE PROCEDURE p_author_exists_2 (author_name VARCHAR2, result OUT

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

    -// The function has a generic type parameter <T> bound to its return value +// The function has a generic type parameter <T> bound to its return value public class FAuthorExists extends org.jooq.impl.AbstractRoutine<BigDecimal> { // Much like Tables, functions have static parameter definitions @@ -2306,14 +2293,14 @@ public class PAuthorExists_2 extends org.jooq.impl.AbstractRoutine<java.lang. // the getters... public BigDecimal getResult() { // [...] public BigDecimal getId() { // [...] -} +}

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

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

    The above configuration is a @@ -2322,7 +2309,7 @@ assertEquals(BigDecimal.ONE, p.getResult()); If you use the generated convenience methods, however, things are much simpler, still:

    -// Every schema has a single Routines class with convenience methods +// Every schema has a single Routines class with convenience methods public final class Routines { // Convenience method to directly call the stored function @@ -2340,10 +2327,10 @@ public final class Routines { // 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")); +assertEquals(BigDecimal.ONE, Procedures.pAuthorExists(configuration, "Paulo"));

    jOOQ's understanding of procedures vs functions

    @@ -2389,7 +2376,7 @@ public final class Routines { 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 ( +CREATE OR REPLACE TYPE u_author_type AS OBJECT ( id NUMBER(7), first_name VARCHAR2(50), last_name VARCHAR2(50), @@ -2399,14 +2386,14 @@ public final class Routines { ) -- 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); @@ -2416,18 +2403,18 @@ author.load(); // The record is now updated with the LOAD implementation's content assertNotNull(author.getFirstName()); -assertNotNull(author.getLastName()); +assertNotNull(author.getLastName());

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

    -
    +
    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 @@ -2474,7 +2461,7 @@ assertNotNull(author.getLastName());

    In Oracle, you would define UDTs like this:

    -CREATE TYPE u_street_type AS OBJECT ( +CREATE TYPE u_street_type AS OBJECT ( street VARCHAR2(100), no VARCHAR2(30) ) @@ -2486,16 +2473,16 @@ CREATE TYPE u_address_type AS OBJECT ( 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 ( +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); +CREATE OR REPLACE PROCEDURE p_check_address (address IN OUT u_address_type);

    Standard JDBC UDT support encourages JDBC-driver developers to implement @@ -2514,7 +2501,7 @@ CREATE OR REPLACE PROCEDURE p_check_address (address IN OUT u_address_type); and as such:

    -// There is an analogy between UDT/Table and UDTRecord/TableRecord... +// There is an analogy between UDT/Table and UDTRecord/TableRecord... public class UAddressType extends UDTImpl<UAddressTypeRecord> { // The UDT meta-model singleton instance @@ -2528,22 +2515,22 @@ public class UAddressType extends UDTImpl<UAddressTypeRecord> { 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 +// 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()); +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 +// 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); +address = Procedures.pCheckAddress(connection, address);

    ARRAY types

    @@ -2578,16 +2565,16 @@ address = Procedures.pCheckAddress(connection, address);

    Example: General ARRAY types

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

    -CREATE TABLE t_arrays ( +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[] +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> { +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 = // [...] @@ -2599,7 +2586,7 @@ 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 @@ -2610,7 +2597,7 @@ public final class Functions { 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_string_array AS VARRAY(4) OF VARCHAR2(20) CREATE TYPE u_number_array AS VARRAY(4) OF NUMBER(7) CREATE TABLE t_arrays ( @@ -2620,7 +2607,7 @@ CREATE TABLE t_arrays ( ) CREATE OR REPLACE FUNCTION f_arrays (in_array u_string_array) -RETURN 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 @@ -2628,7 +2615,7 @@ RETURN u_string_array and other artefacts in Oracle:

    -public class UStringArrayRecord extends ArrayRecordImpl<String> { // [...] +public class UStringArrayRecord extends ArrayRecordImpl<String> { // [...] public class UNumberArrayRecord extends ArrayRecordImpl<Integer> { // [...] public class TArrays extends UpdatableTableImpl<TArraysRecord> { @@ -2640,7 +2627,7 @@ 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

    @@ -2655,7 +2642,7 @@ public final class Functions {

    Some examples:

    --- An example enum type +-- An example enum type CREATE TYPE u_book_status AS ENUM ('SOLD OUT', 'ON STOCK', 'ORDERED') -- An example useage of that enum type @@ -2664,18 +2651,18 @@ CREATE TABLE t_book ( -- [...] status u_book_status -) +)

    The above Postgres ENUM type will be generated as

    -public enum UBookStatus implements EnumType { +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 +// The meta-model class public class TBook extends UpdatableTableImpl<TBookRecord> { // The TableField STATUS binds <T> to UBookStatus @@ -2691,45 +2678,44 @@ public class TBookRecord extends UpdatableRecordImpl<TBookRecord> { // 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.

    -
    +
    Sequences and Serials - +

    Sequences as a source for identity values

    Sequences implement the interface, providing essentially this functionality:

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

    So if you have a sequence like this in Oracle:

    - CREATE SEQUENCE s_author_id + CREATE SEQUENCE s_author_id

    This is what jOOQ will generate:

    -public final class Sequences { +public final class Sequences { // 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); +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); -
    +BigInteger currval = create.currval(Sequences.S_AUTHOR_ID); +BigInteger nextval = create.nextval(Sequences.S_AUTHOR_ID);
    @@ -2739,7 +2725,7 @@ BigInteger nextval = create.nextval(Sequences.S_AUTHOR_ID);
    DSL or fluent API. Where SQL meets Java - +

    Overview

    jOOQ ships with its own DSL (or Domain Specific Language) that @@ -2748,7 +2734,7 @@ BigInteger nextval = create.nextval(Sequences.S_AUTHOR_ID); 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 * @@ -2756,28 +2742,27 @@ SELECT * 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 = + ORDER BY b.titleResult<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(); + .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

    -
    +
    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 @@ -2785,7 +2770,7 @@ create.select() some extensions, is provided by a query like this:

    --- get all authors' first and last names, and the number +-- 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 @@ -2802,13 +2787,13 @@ GROUP BY T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME ORDER BY T_AUTHOR.LAST_NAME ASC NULLS FIRST LIMIT 2 OFFSET 1 - FOR UPDATE + 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); +SelectFromStep select(Field<?>... fields); // Example: -create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()); +create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count());

    jOOQ will return an "intermediary" type to you, representing the @@ -2826,11 +2811,11 @@ create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()); clauses. Let's say you do decide to add a FROM clause, then you can use this method for instance:

    -SelectJoinStep from(TableLike<?>... table); +SelectJoinStep from(TableLike<?>... table); // The example, continued: create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) - .from(T_AUTHOR); + .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 @@ -2839,7 +2824,7 @@ create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) extends . But let's say we add a JOIN:

    -// These join types are supported +// These join types are supported SelectOnStep join(Table<?> table); SelectOnStep leftOuterJoin(Table<?> table); SelectOnStep rightOuterJoin(Table<?> table); @@ -2852,7 +2837,7 @@ SelectJoinStep naturalRightOuterJoin(Table<?> table); // The example, continued: create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) .from(T_AUTHOR) - .join(T_BOOK); + .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 @@ -2860,7 +2845,7 @@ create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) is a top-level interface.

    -... keyFields); @@ -2870,7 +2855,7 @@ 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));]]> + .join(T_BOOK).on(T_BOOK.AUTHOR_ID.equal(T_AUTHOR.ID));]]>

    See the section about @@ -2888,13 +2873,13 @@ create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) 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); +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")); + .where(T_BOOK.LANGUAGE.equal("DE"));

    Now the returned type is a special one, where @@ -2904,20 +2889,20 @@ create.select(TAuthor.FIRST_NAME, TAuthor.LAST_NAME, count()) 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); +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'))); + .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); +SelectHavingStep groupBy(Field<?>... fields); // The example, continued: create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) @@ -2925,10 +2910,10 @@ create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) .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); + .groupBy(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME);

    and the HAVING clause:

    -SelectOrderByStep having(Condition... conditions); +SelectOrderByStep having(Condition... conditions); // The example, continued: create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) @@ -2937,13 +2922,13 @@ create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) .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)); + .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); +SelectLimitStep orderBy(Field<?>... fields); // The example, continued: create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) @@ -2953,7 +2938,7 @@ create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) .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()); + .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 @@ -2962,7 +2947,7 @@ create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) 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); +SelectFinalStep limit(int offset, int numberOfRows); // The example, continued: create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) @@ -2973,13 +2958,13 @@ create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) .groupBy(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME) .having(count().greaterThan(5)) .orderBy(T_AUTHOR.LAST_NAME.asc().nullsFirst()) - .limit(1, 2); + .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(); +SelectFinalStep forUpdate(); // The example, continued: create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) @@ -2991,7 +2976,7 @@ create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) .having(count().greaterThan(5)) .orderBy(T_AUTHOR.LAST_NAME.asc().nullsFirst()) .limit(1, 2) - .forUpdate(); + .forUpdate();

    Now the most relevant super-type of the object we have just created is @@ -3004,7 +2989,7 @@ create.select(T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, count()) section about the :

    -// Just execute the query. +// Just execute the query. int execute(); // Execute the query and retrieve the results @@ -3017,7 +3002,7 @@ Record fetchAny(); // An Exception is thrown if more records were available Record fetchOne(); -// [...] +// [...]

    SELECT from single physical tables

    @@ -3029,22 +3014,21 @@ Record fetchOne(); 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); + 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) +TBook book = create.selectFrom(T_BOOK) .where(TBook.LANGUAGE.equal("DE")) .orderBy(TBook.TITLE) - .fetchAny(); -
    + .fetchAny();
    Table sources - +

    Create complex and nested table sources

    In the relational data model, @@ -3055,7 +3039,7 @@ Record fetchOne(); the type itself provides a rich API for creating joined table sources. See an extract of the Table API:

    - table); TableOnStep join(String sql); @@ -3079,14 +3063,14 @@ 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);]]> +DivideByOnStep divideBy(Table divisor);]]>

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

    - using(Collection> fields); // foreign key relationship information to dynamically render "ON [ condition ... ]" clauses TableOnConditionStep onKey() throws DataAccessException; TableOnConditionStep onKey(TableField... keyFields) throws DataAccessException; -TableOnConditionStep onKey(ForeignKey key);]]> +TableOnConditionStep onKey(ForeignKey key);]]>
    • @@ -3112,13 +3096,13 @@ TableOnConditionStep onKey(ForeignKey key);]]>
    -
    +
    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 @@ -3130,7 +3114,7 @@ TableOnConditionStep onKey(ForeignKey key);]]> which is typically a participant of a condition, and the itself:

    -public interface Condition { +public interface Condition { Condition and(Condition other); Condition and(String sql); Condition and(String sql, Object... bindings); @@ -3144,7 +3128,7 @@ TableOnConditionStep onKey(ForeignKey key);]]> 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 @@ -3155,7 +3139,7 @@ TableOnConditionStep onKey(ForeignKey key);]]> cases. Here are some important API elements in the Field interface:

    - { + { Condition isNull(); Condition isNotNull(); Condition like(T value); @@ -3197,7 +3181,7 @@ TableOnConditionStep onKey(ForeignKey key);]]> 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 @@ -3206,26 +3190,25 @@ TableOnConditionStep onKey(ForeignKey key);]]> .

    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 (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') +(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(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")))); -
    +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 +SELECT a.ID, b.ID FROM T_AUTHOR a - JOIN T_BOOK b on a.ID = b.AUTHOR_ID + JOIN T_BOOK b on a.ID = b.AUTHOR_ID

    In this example, we are aliasing Tables, calling them a and b. @@ -3237,36 +3220,36 @@ T_BOOK.TYPE_CODE.in(create.select(T_TYPES.CODE).from(T_TYPES)).and(T_BOOK.LANGUA Here is how you can create Table aliases in jOOQ:

    -Table<TBookRecord> book = T_BOOK.as("b"); +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"); +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); + 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;]]> +Field authorID = author.ID;]]>

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

    -create.select(authorID, bookID) +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)) + .join(book).on(author.ID.equal(book.AUTHOR_ID))

    Aliasing nested selects as tables

    @@ -3279,27 +3262,26 @@ create.select(author.ID, book.ID)

    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 + 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; +GROUP BY FIRST_NAME, LAST_NAME;

    Here is how it's done with jOOQ:

    -Record record = create.select( +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(); + .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")); -
    +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 @@ -3317,7 +3299,7 @@ System.out.println("Books : " + record.getValue("books")); 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 ( @@ -3329,8 +3311,7 @@ System.out.println("Books : " + record.getValue("books")); SELECT T_BOOK.* FROM T_BOOK JOIN T_AUTHOR ON (T_BOOK.AUTHOR_ID = T_AUTHOR.ID - AND T_AUTHOR.BORN = 1920) -create.select() + AND T_AUTHOR.BORN = 1920)create.select() .from(T_BOOK) .where(T_BOOK.AUTHOR_ID.in( create.select(T_AUTHOR.ID).from(T_AUTHOR) @@ -3341,14 +3322,14 @@ SELECT T_BOOK.* 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))); -
    + .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:

    @@ -3361,8 +3342,8 @@ create.select(T_BOOK.getFields())

    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); +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 @@ -3371,70 +3352,68 @@ Condition notExists(Select<?> query); convenience methods, where they might be useful. For instance in the itself:

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

    Or in the :

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

    Or in the :

    -SelectConditionStep andExists(Select<?> select); +SelectConditionStep andExists(Select<?> select); SelectConditionStep andNotExists(Select<?> select); SelectConditionStep orExists(Select<?> select); -SelectConditionStep orNotExists(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() + 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() + 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 equal(Select<?> query); Condition equalAny(Select<?> query); -Condition equalAll(Select<?> query); +Condition equalAll(Select<?> query);

    Selecting from a SELECT - SELECT acts as a Table

    @@ -3442,16 +3421,16 @@ Condition equalAll(Select<?> query); 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 + SELECT AUTHOR_ID, count(*) books FROM T_BOOK GROUP BY AUTHOR_ID -ORDER BY books DESC +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 @@ -3460,8 +3439,7 @@ ORDER BY books DESC ORDER BY nested.books DESC - -Table<Record> nested = +Table<Record> nested = create.select(T_BOOK.AUTHOR_ID, count().as("books")) .from(T_BOOK) .groupBy(T_BOOK.AUTHOR_ID).asTable("nested"); @@ -3469,7 +3447,7 @@ ORDER BY nested.books DESC 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.

    @@ -3481,7 +3459,7 @@ create.select(nested.getFields()) 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 @@ -3491,8 +3469,7 @@ ORDER BY books DESC - -// The type of books cannot be inferred from the Select<?> +// The type of books cannot be inferred from the Select<?> Field<Object> books = create.selectCount() .from(T_BOOK) @@ -3501,14 +3478,14 @@ Field<Object> 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 @@ -3516,30 +3493,29 @@ create.select(T_AUTHOR.ID, books) . It consists of these methods:

    -public interface Select<R extends Record> { +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) + WHERE AUTHOR_ID = 1create.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 @@ -3549,7 +3525,7 @@ create.select(T_BOOK.TITLE) 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 +// 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))); @@ -3557,7 +3533,7 @@ Select<?> union = // 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()); + .orderBy(union.getField(T_BOOK.AUTHOR_ID).descending());

    This example does not seem surprising, when you have read the previous chapters about @@ -3565,14 +3541,14 @@ create.select(union.getField(T_BOOK.TITLE)) But when you check out the rendered SQL:

    --- alias_38173 is an example of a generated alias, +-- 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 +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 @@ -3581,14 +3557,14 @@ ORDER BY alias_38173.AUTHOR_ID DESC

    Several UNIONs

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

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

    UNION and the ORDER BY clause

    @@ -3600,7 +3576,7 @@ part1.union(part2).union(part3).union(part4); 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 @@ -3610,8 +3586,7 @@ part1.union(part2).union(part3).union(part4); ) UNION ( SELECT * FROM emp WHERE dept = 'R&D' ORDER BY salary LIMIT 1 -) -create.selectFrom(EMP).where(DEPT.equal("IT")) +)create.selectFrom(EMP).where(DEPT.equal("IT")) .orderBy(SALARY).limit(1) .union( create.selectFrom(EMP).where(DEPT.equal("Marketing")) @@ -3622,20 +3597,20 @@ create.selectFrom(EMP).where(DEPT.equal("R&D") - +

    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:

    @@ -3653,7 +3628,7 @@ create.selectFrom(EMP).where(DEPT.equal("R&D")

    Functions

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

    - rpad(Field field, Field length); + 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); @@ -3666,14 +3641,14 @@ 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);]]> +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); @@ -3700,18 +3675,17 @@ 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_AUTHORcreate.select(max(ID).add(1).as("next_id")) .from(T_AUTHOR); - +

    See also the section about

    @@ -3724,16 +3698,15 @@ AggregateFunction varSamp(Field field); 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, ", ") +GROUP BY AUTHOR_IDcreate.select(listAgg(BOOK.TITLE, ", ") .withinGroupOrderBy(BOOK.TITLE)) .from(BOOK) .groupBy(BOOK.AUTHOR_ID) - +

    Window functions

    @@ -3749,27 +3722,26 @@ GROUP BY AUTHOR_ID 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, + FROM transactionscreate.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 @@ -3794,21 +3766,21 @@ GROUP BY AUTHOR_ID 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; +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 +// 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) { // [...] +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 @@ -3816,15 +3788,14 @@ public static Field<BigDecimal> fAuthorExists(String authorName) { // [... 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)) + WHERE F_AUTHOR_EXISTS(T_PERSON.NAME) = 1create.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 @@ -3832,13 +3803,13 @@ create.select(T_PERSON.NAME) 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 @@ -3850,19 +3821,18 @@ create.select(T_PERSON.NAME) 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 + 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)); + 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)); - + + SELECT SYSDATE + 3 FROM DUAL;create.select(currentTimestamp().add(3)); +

    For more advanced datetime arithmetic, use the Factory's timestampDiff() and dateDiff() functions, @@ -3877,30 +3847,29 @@ create.select(T_PERSON.NAME)

    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') -  +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' @@ -3911,8 +3880,7 @@ END CASE T_AUTHOR.FIRST_NAME WHEN 'Paulo' THEN 'brazilian' WHEN 'George' THEN 'english' ELSE 'unknown' -END -create.decode() +END create.decode() .when(T_AUTHOR.FIRST_NAME.equal("Paulo"), "brazilian") .when(T_AUTHOR.FIRST_NAME.equal("George"), "english") .otherwise("unknown"); @@ -3923,7 +3891,7 @@ 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 @@ -3936,36 +3904,35 @@ create.decode().value(T_AUTHOR.FIRST_NAME)

    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 +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 * +SELECT * FROM T_AUTHOR ORDER BY CASE FIRST_NAME WHEN 'Paulo' THEN 1 WHEN 'George' THEN 2 ELSE null - END + 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() +create.select() .from(T_AUTHOR) .orderBy(T_AUTHOR.FIRST_NAME.sortAsc("Paulo", "George")) - .execute(); -
    + .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 @@ -3978,17 +3945,17 @@ ORDER BY CASE FIRST_NAME WHEN 'Paulo' THEN 1 ). In those cases you would write SQL type CASTs like this:

    --- Let's say, your Postgres column LAST_NAME was VARCHAR(30) +-- 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 +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)); + 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)); + create.select(TAuthor.LAST_NAME.cast(String.class));

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

    -public interface Field<T> { +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); @@ -4002,14 +3969,13 @@ public class Factory { <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 @@ -4040,7 +4006,7 @@ public class Factory {

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

    - 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);]]> +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"); @@ -4110,7 +4076,7 @@ create.select(LAST_NAME, COUNT1, COUNT2) // Use plain SQL again as fields in GROUP BY and ORDER BY clauses .groupBy(LAST_NAME) - .orderBy(LAST_NAME);]]> + .orderBy(LAST_NAME);]]>

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

    @@ -4125,7 +4091,7 @@ create.select(LAST_NAME, COUNT1, COUNT2)
  • Your SQL is inserted into jOOQ queries without further checks. Hence, jOOQ can't prevent SQL injection.
  • -
    +
    @@ -4134,16 +4100,16 @@ create.select(LAST_NAME, COUNT1, COUNT2)
    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 @@ -4158,7 +4124,7 @@ create.select(LAST_NAME, COUNT1, COUNT2)

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

    - + @@ -4174,10 +4140,10 @@ create.select(LAST_NAME, COUNT1, COUNT2) [ ... ... ] - ]]> + ]]>

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

    - { + { /** * English @@ -4205,7 +4171,7 @@ create.select(LAST_NAME, COUNT1, COUNT2) 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 @@ -4228,20 +4194,20 @@ create.select(LAST_NAME, COUNT1, COUNT2) 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 @@ -4250,13 +4216,13 @@ create.select(LAST_NAME, COUNT1, COUNT2) 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 @@ -4273,7 +4239,7 @@ create.select(LAST_NAME, COUNT1, COUNT2) a Converter like this:

    - +]]>

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

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

    Using Converters in generated code

    @@ -4332,7 +4298,7 @@ create.select(T_AUTHOR.DATE_OF_BIRTH) fields that start with DATE_OF_

    - + @@ -4355,20 +4321,20 @@ create.select(T_AUTHOR.DATE_OF_BIRTH) .*\.DATE_OF_.* -]]> +]]>

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

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

    This means that the bound of <T> will be GregorianCalendar, @@ -4377,11 +4343,11 @@ create.select(T_AUTHOR.DATE_OF_BIRTH) :

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

    Read more about advanced code generation configuration in @@ -4398,13 +4364,13 @@ create.selectFrom(T_AUTHOR) you may choose to extend instead, which provides some enum-specific default behaviour.

    -
    +
    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 @@ -4431,7 +4397,7 @@ create.selectFrom(T_AUTHOR) class, that you can equip your Factory's settings with. Take the following example:

    -Settings settings = new Settings() +Settings settings = new Settings() .withRenderMapping(new RenderMapping() .withSchemata( new MappedSchema().withInput("DEV") @@ -4441,11 +4407,11 @@ create.selectFrom(T_AUTHOR) Factory create = new Factory(connection, SQLDialect.ORACLE, settings); // Run queries with the "mapped" factory -create.selectFrom(T_AUTHOR).fetch(); +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 + SELECT * FROM MY_BOOK_WORLD.T_AUTHOR

    Even if T_AUTHOR was generated from DEV.

    Mapping several schemata

    @@ -4455,7 +4421,7 @@ create.selectFrom(T_AUTHOR).fetch(); their own LOG schema instance. Then you can enhance your RenderMapping like this (e.g. using an XML configuration file):

    - + @@ -4468,11 +4434,11 @@ create.selectFrom(T_AUTHOR).fetch(); -]]> +]]>

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

    -Settings settings = JAXB.unmarshal(new File("jooq-runtime.xml"), Settings.class); +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 @@ -4485,29 +4451,29 @@ create.selectFrom(T_AUTHOR).fetch(); the Factory's underlying Connection. Many RDBMS support a USE or SET SCHEMA command, which you can call like this:

    -// Set the default schema +// 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(); +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 +-- 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() +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(); +create.selectFrom(T_AUTHOR).fetch();

    Mapping of tables

    Not only schemata can be mapped, but also tables. If you are not the @@ -4518,7 +4484,7 @@ create.selectFrom(T_AUTHOR).fetch(); applied to all of your tables. This can be achieved by creating the following mapping:

    -Settings settings = new Settings() +Settings settings = new Settings() .withRenderMapping(new RenderMapping() .withSchemata( new MappedSchema().withInput("DEV") @@ -4531,10 +4497,10 @@ create.selectFrom(T_AUTHOR).fetch(); Factory create = new Factory(connection, SQLDialect.ORACLE, settings); // Run queries with the "mapped" factory -create.selectFrom(T_AUTHOR).fetch(); +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 +SELECT * FROM MY_BOOK_WORLD.MY_APP__T_AUTHOR

    Table mapping and schema mapping can be applied independently, by specifying several MappedSchema entries @@ -4550,7 +4516,7 @@ create.selectFrom(T_AUTHOR).fetch(); dedicated developer databases, and a common integration database. In the code generation configuration, you would then write.

    - + LUKAS_DEV_SCHEMA @@ -4558,19 +4524,19 @@ create.selectFrom(T_AUTHOR).fetch(); PROD -]]> +]]>

    See the manual's section about for more details

    -
    +
    Execute listeners and the jOOQ Console - +

    ExecuteListener

    The @@ -4588,7 +4554,7 @@ create.selectFrom(T_AUTHOR).fetch(); the number of queries per type that are being executed using jOOQ:

    - STATISTICS = new HashMap(); @@ -4604,40 +4570,40 @@ public class StatisticsListener extends DefaultExecuteListener { STATISTICS.put(ctx.type(), count + 1); } -}]]> +}]]>

    Now, configure jOOQ's runtime to load your listener

    - + 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 - 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 +15:16:52,983 INFO - OTHER : 30 executions

    Please read the ExecuteListener Javadoc @@ -4689,18 +4655,18 @@ for (ExecuteType type : ExecuteType.values()) { in the Factory's settings. When using XML settings:

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

    Or when using programmatic settings:

    - +Factory factory = new Factory(connection, dialect, settings);]]>

    In-process mode

    @@ -4710,7 +4676,7 @@ Factory factory = new Factory(connection, dialect, settings);]]> previously documented settings and launch the Console as follows:

    - +]]>

    Only in the in-process mode, you can execute ad-hoc queries directly @@ -4778,74 +4744,74 @@ catch (Exception ignore) {} connect to:

    -// Create a new RemoteDebuggerServer in your application that listens to +// Create a new RemoteDebuggerServer in your application that listens to // incoming connections on a given port -SERVER = new RemoteDebuggerServer(DEBUGGER_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] +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.

    -
    +
    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 +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) +create.select(FIRST_NAME, LAST_NAME) .hint("/*+ALL_ROWS*/") - .from(T_AUTHOR); + .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

    -
    +
    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:

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

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

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

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

    - paths = ora.select(ora.sysConnectByPath(DIRECTORY.NAME, "/").substring(2)) @@ -4853,10 +4819,10 @@ create.select(create.rownum()) .connectBy(ora.prior(DIRECTORY.ID).equal(DIRECTORY.PARENT_ID)) .startWith(DIRECTORY.PARENT_ID.isNull()) .orderBy(ora.literal(1)) - .fetch(0);]]> + .fetch(0);]]>

    The output might then look like this

    -+------------------------------------------------+ ++------------------------------------------------+ |substring | +------------------------------------------------+ |C: | @@ -4866,22 +4832,21 @@ create.select(create.rownum()) |C:/eclipse/eclipse.exe | +------------------------------------------------+ |...21 record(s) truncated... - -
    +
    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 .. +-- SELECT .. FROM table PIVOT (aggregateFunction [, aggregateFunction] FOR column IN (expression [, expression])) --- WHERE .. +-- WHERE ..

    The PIVOT clause is available from the @@ -4891,13 +4856,13 @@ create.select(create.rownum()) 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 @@ -4907,12 +4872,12 @@ create.select(create.rownum()) The following is an approximate definition of a relational division:

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

    @@ -4920,11 +4885,11 @@ B = C ÷ A by using the following syntax:

    -C.divideBy(B).on(C.ID.equal(B.C_ID)).returning(C.TEXT) +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" +SELECT DISTINCT C.TEXT FROM C "c1" WHERE NOT EXISTS ( SELECT 1 FROM B WHERE NOT EXISTS ( @@ -4932,7 +4897,7 @@ WHERE NOT EXISTS ( WHERE "c2".TEXT = "c1".TEXT AND "c2".ID = B.C_ID ) -) +)

    Or in plain text: Find those TEXT values in C @@ -4956,13 +4921,13 @@ WHERE NOT EXISTS ( http://www.simple-talk.com/sql/t-sql-programming/divided-we-stand-the-sql-of-relational-division/ - +

    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 @@ -4971,11 +4936,11 @@ WHERE NOT EXISTS (

    XML

    Export your results as XML:

    -// Fetch books and format them as XML -String xml = create.selectFrom(T_BOOK).fetch().formatXML(); +// 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:

    - + @@ -4994,34 +4959,34 @@ String xml = create.selectFrom(T_BOOK).fetch().formatXML(); Animal Farm -]]> +]]>

    CSV

    Export your results as CSV:

    -// Fetch books and format them as CSV -String csv = create.selectFrom(T_BOOK).fetch().formatCSV(); +// 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 +ID;AUTHOR_ID;TITLE 1;1;1984 -2;1;Animal Farm +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(); +// 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"]]} +{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(); +// 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 @@ -5041,27 +5006,26 @@ String html = create.selectFrom(T_BOOK).fetch().formatHTML(); Animal Farm -]]> +]]>

    Text

    Export your results as text:

    -// Fetch books and format them as text -String text = create.selectFrom(T_BOOK).fetch().format(); +// 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| -+---+---------+-----------+ -
    ++---+---------+-----------+
    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 @@ -5073,24 +5037,24 @@ String text = create.selectFrom(T_BOOK).fetch().format(); exported previously, by jOOQ's exporting functionality, and then modified in Microsoft Excel or any other spreadsheet tool:

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

    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); +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(); + .execute();

    Here are various other examples:

    -// Ignore the AUTHOR_ID column from the CSV file when inserting +// Ignore the AUTHOR_ID column from the CSV file when inserting create.loadInto(T_AUTHOR) .loadCSV(inputstream) .fields(ID, null, TITLE) @@ -5131,14 +5095,14 @@ create.loadInto(T_AUTHOR) .loadCSV(inputstream) .fields(ID, null, TITLE) - .execute(); + .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(); + loader = /* .. */ .execute(); // The number of processed rows int processed = loader.processed(); @@ -5161,17 +5125,17 @@ int rowIndex = error.rowIndex(); String[] row = error.row(); // The query that caused the error -Query query = error.query();]]> +Query query = error.query();]]>

    XML

    This will be implemented soon...

    -
    +
    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

    @@ -5182,7 +5146,7 @@ Query query = error.query();]]>

    In code, this looks like the following snippet:

    - +int[] result = stmt.executeBatch();]]>

    This will also be supported by jOOQ

    jOOQ supports executing queries in batch mode as follows:

    - -
    + .execute();]]>