diff --git a/jOOQ-website/css/jooq.css b/jOOQ-website/css/jooq.css index 8aad0c307f..b185521ad7 100644 --- a/jOOQ-website/css/jooq.css +++ b/jOOQ-website/css/jooq.css @@ -16,13 +16,6 @@ body { padding: 0; } -hr { - border: 0; - height: 5px; - color: #000; - background-color: #000; -} - h1, h2, h3, h4, h5, h6 { font-family: 'Georgia',Serif; font-weight: normal; diff --git a/jOOQ-website/frame.php b/jOOQ-website/frame.php index bc247ed8bd..3b52c689f6 100644 --- a/jOOQ-website/frame.php +++ b/jOOQ-website/frame.php @@ -83,9 +83,8 @@
diff --git a/jOOQ-website/manual/DSL/SELECT/index.php b/jOOQ-website/manual/DSL/SELECT/index.php index 214ffca0d4..67ffd71c96 100644 --- a/jOOQ-website/manual/DSL/SELECT/index.php +++ b/jOOQ-website/manual/DSL/SELECT/index.php @@ -7,7 +7,12 @@ function printH1() { print "Complete SELECT syntax"; } function getSlogan() { - return ""; + return " + A SELECT statement is more than just the R in CRUD. It allows for + transforming your relational data into any other form using concepts + such as equi-join, semi-join, anti-join, outer-join and much more. jOOQ + helps you think in precisely those relational concepts. + "; } function printContent() { global $root; @@ -16,7 +21,271 @@ function printContent() {When you don't just perform CRUD (i.e. SELECT * FROM your_table WHERE ID = ?), + you're usually generating new types using custom projections. With jOOQ, this is + as intuitive, as if using SQL directly. A more or less complete example of the "standard" SQL syntax, plus + some extensions, is provided by a query like this: +
+ ++-- get all authors' first and last names, and the number +-- of books they've written in German, if they have written +-- more than five books in German in the last three years +-- (from 2011), and sort those authors by last names +-- limiting results to the second and third row, locking +-- the rows for a subsequent update... whew! + + SELECT T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, COUNT(*) + FROM T_AUTHOR + JOIN T_BOOK ON T_AUTHOR.ID = T_BOOK.AUTHOR_ID + WHERE T_BOOK.LANGUAGE = 'DE' + AND T_BOOK.PUBLISHED > '2008-01-01' +GROUP BY T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME + HAVING COUNT(*) > 5 +ORDER BY T_AUTHOR.LAST_NAME ASC NULLS FIRST + LIMIT 2 + OFFSET 1 + FOR UPDATE+ +
So that's daily business. How to do it with jOOQ: When you first create a SELECT statement using the Factory's select() methods
++SelectFromStep select(Field<?>... fields); + +// Example: +create.select(TAuthor.FIRST_NAME, TAuthor.LAST_NAME, create.count());+ +
+ jOOQ will return an "intermediary" type to you, representing the + SELECT statement about to be created (by the way, check out the + section on aggregate operators + to learn more about the COUNT(*) + function). This type is the + org.jooq.SelectFromStep. + When you have a reference + to this type, you may add a FROM clause, although that clause is + optional. This is reflected by the fact, that the SelectFromStep type + extends + org.jooq.SelectJoinStep, + which allows for adding the subsequent + clauses. Let's say you do decide to add a FROM clause, then you can + use this method for instance: +
++SelectJoinStep from(TableLike<?>... table); + +// The example, continued: +create.select(TAuthor.FIRST_NAME, TAuthor.LAST_NAME, create.count()) + .from(T_AUTHOR);+ +
After adding the table-like structures (mostly just Tables) to + select from, you may optionally choose to add a JOIN clause, as the + type returned by jOOQ is the step where you can add JOINs. Again, + adding these clauses is optional, as the + org.jooq.SelectJoinStep extends + org.jooq.SelectWhereStep. + But let's say we add a JOIN:
++// These join types are supported +SelectOnStep join(Table<?> table); +SelectOnStep leftOuterJoin(Table<?> table); +SelectOnStep rightOuterJoin(Table<?> table); +SelectOnStep fullOuterJoin(Table<?> table); +SelectJoinStep crossJoin(Table<?> table); +SelectJoinStep naturalJoin(Table<?> table); +SelectJoinStep naturalLeftOuterJoin(Table<?> table); +SelectJoinStep naturalRightOuterJoin(Table<?> table); + +// The example, continued: +create.select(TAuthor.FIRST_NAME, TAuthor.LAST_NAME, create.count()) + .from(T_AUTHOR) + .join(T_BOOK);+ +
Now, if you do add a JOIN clause, you have to specify the JOIN .. ON + condition before you can add more clauses. That's not an optional step + for some JOIN types. This is reflected by the fact that + org.jooq.SelectOnStep + is a top-level interface.
+ ++// These join conditions are supported +SelectJoinStep on(Condition... conditions); +SelectJoinStep using(Field<?>... fields); + +// The example, continued: +create.select(TAuthor.FIRST_NAME, TAuthor.LAST_NAME, create.count()) + .from(T_AUTHOR) + .join(T_BOOK).on(TBook.AUTHOR_ID.equal(TAuthor.ID));+ +
See the section about + Conditions + to learn more about the many ways + to create Conditions in jOOQ. Now we're half way through. As you can + see above, we're back to the SelectJoinStep. This means, we can + re-iterate and add another JOIN clause, just like in SQL. Or we go on + to the next step, adding conditions in the + org.jooq.SelectWhereStep:
+
+SelectConditionStep where(Condition... conditions);
+
+// The example, continued:
+create.select(TAuthor.FIRST_NAME, TAuthor.LAST_NAME, create.count())
+ .from(T_AUTHOR)
+ .join(T_BOOK).on(TBook.AUTHOR_ID.equal(TAuthor.ID))
+ .where(TBook.LANGUAGE.equal("DE"));
+
+ Now the returned type + org.jooq.SelectConditionStep is a special one, where + you can add more conditions to the already existing WHERE clause. + Every time you add a condition, you will return to that + SelectConditionStep, as the number of additional conditions is + unlimited. Note that of course you can also just add a single combined + condition, if that is more readable or suitable for your use-case. + Here's how we add another condition:
+
+SelectConditionStep and(Condition condition);
+
+// The example, continued:
+create.select(TAuthor.FIRST_NAME, TAuthor.LAST_NAME, create.count())
+ .from(T_AUTHOR)
+ .join(T_BOOK).on(TBook.AUTHOR_ID.equal(TAuthor.ID))
+ .where(TBook.LANGUAGE.equal("DE"))
+ .and(TBook.PUBLISHED.greaterThan(parseDate('2008-01-01')));
+
+ Let's assume we have that method parseDate() creating a + java.sql.Date for us. + Then we'll continue adding the GROUP BY clause +
+
+SelectHavingStep groupBy(Field<?>... fields);
+
+// The example, continued:
+create.select(TAuthor.FIRST_NAME, TAuthor.LAST_NAME, create.count())
+ .from(T_AUTHOR)
+ .join(T_BOOK).on(TBook.AUTHOR_ID.equal(TAuthor.ID))
+ .where(TBook.LANGUAGE.equal("DE"))
+ .and(TBook.PUBLISHED.greaterThan(parseDate('2008-01-01')))
+ .groupBy(TAuthor.FIRST_NAME, TAuthor.LAST_NAME);
+
+ and the HAVING clause:
+
+SelectOrderByStep having(Condition... conditions);
+
+// The example, continued:
+create.select(TAuthor.FIRST_NAME, TAuthor.LAST_NAME, create.count())
+ .from(T_AUTHOR)
+ .join(T_BOOK).on(TBook.AUTHOR_ID.equal(TAuthor.ID))
+ .where(TBook.LANGUAGE.equal("DE"))
+ .and(TBook.PUBLISHED.greaterThan(parseDate('2008-01-01')))
+ .groupBy(TAuthor.FIRST_NAME, TAuthor.LAST_NAME)
+ .having(create.count().greaterThan(5));
+
+ and the ORDER BY clause. Some RDBMS support NULLS FIRST and NULLS + LAST extensions to the ORDER BY clause. If this is not supported by + the RDBMS, then the behaviour is simulated with an additional CASE + WHEN ... IS NULL THEN 1 ELSE 0 END clause.
+
+SelectLimitStep orderBy(Field<?>... fields);
+
+// The example, continued:
+create.select(TAuthor.FIRST_NAME, TAuthor.LAST_NAME, create.count())
+ .from(T_AUTHOR)
+ .join(T_BOOK).on(TBook.AUTHOR_ID.equal(TAuthor.ID))
+ .where(TBook.LANGUAGE.equal("DE"))
+ .and(TBook.PUBLISHED.greaterThan(parseDate('2008-01-01')))
+ .groupBy(TAuthor.FIRST_NAME, TAuthor.LAST_NAME)
+ .having(create.count().greaterThan(5))
+ .orderBy(TAuthor.LAST_NAME.asc().nullsFirst());
+
+ and finally the LIMIT clause. Most dialects have a means of limiting + the number of result records (except Oracle). Some even support having + an OFFSET to the LIMIT clause. Even if your RDBMS does not support the + full LIMIT ... OFFSET ... clause, jOOQ + will simulate the LIMIT clause using nested selects and filtering on + ROWNUM (for Oracle), or on ROW_NUMBER() (for DB2 and SQL + Server):
+
+SelectFinalStep limit(int offset, int numberOfRows);
+
+// The example, continued:
+create.select(TAuthor.FIRST_NAME, TAuthor.LAST_NAME, create.count())
+ .from(T_AUTHOR)
+ .join(T_BOOK).on(TBook.AUTHOR_ID.equal(TAuthor.ID))
+ .where(TBook.LANGUAGE.equal("DE"))
+ .and(TBook.PUBLISHED.greaterThan(parseDate('2008-01-01')))
+ .groupBy(TAuthor.FIRST_NAME, TAuthor.LAST_NAME)
+ .having(create.count().greaterThan(5))
+ .orderBy(TAuthor.LAST_NAME.asc().nullsFirst())
+ .limit(1, 2);
+
+ In the final step, there are some proprietary extensions available + only in some RDBMS. One of those extensions are the FOR UPDATE + (supported in most RDBMS) and FOR SHARE clauses (supported only in + MySQL and Postgres):
+
+SelectFinalStep forUpdate();
+
+// The example, continued:
+create.select(TAuthor.FIRST_NAME, TAuthor.LAST_NAME, create.count())
+ .from(T_AUTHOR)
+ .join(T_BOOK).on(TBook.AUTHOR_ID.equal(TAuthor.ID))
+ .where(TBook.LANGUAGE.equal("DE"))
+ .and(TBook.PUBLISHED.greaterThan(parseDate('2008-01-01')))
+ .groupBy(TAuthor.FIRST_NAME, TAuthor.LAST_NAME)
+ .having(create.count().greaterThan(5))
+ .orderBy(TAuthor.LAST_NAME.asc().nullsFirst())
+ .limit(1, 2)
+ .forUpdate();
+
+ + Now the most relevant super-type of the object we have just created is + org.jooq.Select<Record>. + This type can be reused in various expressions such as in the + UNION and other set operations, + Nested select statements using the EXISTS operator, + etc. If you just want to execute this select + statement, you can choose any of these methods as discussed in the + section about the ResultQuery: +
+ ++// Just execute the query. +int execute() throws SQLException; + +// Execute the query and retrieve the results +Result<Record> fetch() throws SQLException; + +// Execute the query and retrieve the first Record +Record fetchAny() throws SQLException; + +// Execute the query and retrieve the single Record +// An Exception is thrown if more records were available +Record fetchOne() throws SQLException; + +// [...]+ + +
A very similar API is available, if you want to select from single + physical tables in order to retrieve TableRecords or even + UpdatableRecords (see also the manual's section on + SelectQuery vs SimpleSelectQuery). + The decision, which type of select to create is + already made at the very first step, when you create the SELECT + statement with the Factory:
+ +public <R extends Record> SimpleSelectWhereStep<R> selectFrom(Table<R> table);+
As you can see, there is no way to further restrict/project the selected + fields. This just selects all known TableFields in the supplied Table, + and it also binds <R extends Record> to your Table's associated + Record. An example of such a Query would then be:
+
+TBook book = create.selectFrom(T_BOOK)
+ .where(TBook.LANGUAGE.equal("DE"))
+ .orderBy(TBook.TITLE)
+ .fetchAny();
+ | The jOOQ User Manual : DSL or fluent API. Where SQL meets Java : Complete SELECT syntax | previous : next |