From a4416b4545f70b499e294eea8cee1932f41ae33b Mon Sep 17 00:00:00 2001
From: Lukas Eder If you are closely coupling your application to an Oracle 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: This can be done in jOOQ using the .connectBy(Condition) clauses in your SELECT statement: 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 If you are using jOOQ for scripting purposes or in a slim, unlayered
+ application server, you might be interested in using jOOQ's exporting
+ functionality (see also importing functionality). You can export any
+ Result<Record> into any of these formats: Export your results as XML: The above query will result in an XML document looking like the following one: Export your results as CSV: The above query will result in a CSV document looking like the following one: Export your results as JSON: The above query will result in a JSON document looking like the following one: Export your results as HTML: The above query will result in an HTML document looking like the following one: Export your results as text: The above query will result in a text document looking like the following one: If you are using jOOQ for scripting purposes or in a slim, unlayered
+ application server, you might be interested in using jOOQ's importing
+ functionality (see also exporting functionality). You can import data
+ directly into a table from any of these formats: The below CSV data represents two author records that may have been
+ exported previously, by jOOQ's exporting functionality, and then
+ modified in Microsoft Excel or any other spreadsheet tool: With jOOQ, you can load this data using various parameters from the
+ loader API. A simple load may look like this: Here are various other examples: 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: This will be implemented soon...
-
-The jOOQ User Manual : Advanced topics : The Oracle CONNECT BY clause for hierarchical queries previous : next
+The jOOQ User Manual : Advanced topics : The Oracle CONNECT BY clause previous : next
+
+ CONNECT BY .. STARTS WITH
+
+-- SELECT ..
+-- FROM ..
+-- WHERE ..
+ CONNECT BY [NOCYCLE] condition [AND condition, ...] [START WITH condition]
+-- GROUP BY ..
+
+// 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();
+
+
+ OracleFactory ora = new OracleFactory(connection);
+
+ List<?> paths =
+ ora.select(ora.sysConnectByPath(Directory.NAME, "/").substring(2))
+ .from(Directory)
+ .connectBy(ora.prior(Directory.ID).equal(Directory.PARENT_ID))
+ .startWith(Directory.PARENT_ID.isNull())
+ .orderBy(ora.literal(1))
+ .fetch(0);
+
+
++------------------------------------------------+
+|substring |
++------------------------------------------------+
+|C: |
+|C:/eclipse |
+|C:/eclipse/configuration |
+|C:/eclipse/dropins |
+|C:/eclipse/eclipse.exe |
++------------------------------------------------+
+|...21 record(s) truncated...
+
+
-
The jOOQ User Manual : Advanced topics : The Oracle CONNECT BY clause for hierarchical queries previous : next
+The jOOQ User Manual : Advanced topics : The Oracle CONNECT BY clause previous : next
+
+ Exporting with jOOQ
+ XML
+
+// Fetch books and format them as XML
+String xml = create.selectFrom(T_BOOK).fetch().formatXML();
+
+
+<!-- Find the XSD definition on www.jooq.org: -->
+<jooq-export:result xmlns:jooq-export="http://www.jooq.org/xsd/jooq-export-1.6.2.xsd">
+ <fields>
+ <field name="ID"/>
+ <field name="AUTHOR_ID"/>
+ <field name="TITLE"/>
+ </fields>
+ <records>
+ <record>
+ <value field="ID">1</value>
+ <value field="AUTHOR_ID">1</value>
+ <value field="TITLE">1984</value>
+ </record>
+ <record>
+ <value field="ID">2</value>
+ <value field="AUTHOR_ID">1</value>
+ <value field="TITLE">Animal Farm</value>
+ </record>
+ </records>
+</jooq-export:result>
+
+ CSV
+
+// Fetch books and format them as CSV
+String csv = create.selectFrom(T_BOOK).fetch().formatCSV();
+
+
+ID;AUTHOR_ID;TITLE
+1;1;1984
+2;1;Animal Farm
+
+
+ JSON
+
+// Fetch books and format them as JSON
+String json = create.selectFrom(T_BOOK).fetch().formatJSON();
+
+{fields:["ID","AUTHOR_ID","TITLE"],
+ records:[[1,1,"1984"],[2,1,"Animal Farm"]]}
+
+ HTML
+
+// Fetch books and format them as HTML
+String html = create.selectFrom(T_BOOK).fetch().formatHTML();
+
+<table>
+ <thead>
+ <tr>
+ <th>ID</th>
+ <th>AUTHOR_ID</th>
+ <th>TITLE</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>1</td>
+ <td>1</td>
+ <td>1984</td>
+ </tr>
+ <tr>
+ <td>2</td>
+ <td>1</td>
+ <td>Animal Farm</td>
+ </tr>
+ </tbody>
+</table>
+
+ Text
+
+// Fetch books and format them as text
+String text = create.selectFrom(T_BOOK).fetch().format();
+
+
++---+---------+-----------+
+| ID|AUTHOR_ID|TITLE |
++---+---------+-----------+
+| 1| 1|1984 |
+| 2| 1|Animal Farm|
++---+---------+-----------+
+
-
The jOOQ User Manual : Advanced topics : Exporting data to XML, CSV, JSON, HTML, Text previous : next
+The jOOQ User Manual : Advanced topics : Exporting to XML, CSV, JSON, HTML, Text previous : next
-
-The jOOQ User Manual : Advanced topics : Importing data from XML, CSV previous
+The jOOQ User Manual : Advanced topics : Importing data from XML, CSV previous
+
+ Importing with jOOQ
+ CSV
+
+ID;AUTHOR_ID;TITLE
+1;1;1984
+2;1;Animal Farm
+
+
+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();
+
+
+// Ignore the AUTHOR_ID column from the CSV file when inserting
+create.loadInto(T_AUTHOR)
+ .loadCSV(inputstream)
+ .fields(ID, null, TITLE)
+ .execute();
+
+// Specify behaviour for duplicate records.
+create.loadInto(T_AUTHOR)
+
+ // choose any of these methods
+ .onDuplicateKeyUpdate()
+ .onDuplicateKeyIgnore()
+ .onDuplicateKeyError() // the default
+
+ .loadCSV(inputstream)
+ .fields(ID, null, TITLE)
+ .execute();
+
+// Specify behaviour when errors occur.
+create.loadInto(T_AUTHOR)
+
+ // choose any of these methods
+ .onErrorIgnore()
+ .onErrorAbort() // the default
+
+ .loadCSV(inputstream)
+ .fields(ID, null, TITLE)
+ .execute();
+
+// Specify transactional behaviour where this is possible
+// (e.g. not in container-managed transactions)
+create.loadInto(T_AUTHOR)
+
+ // choose any of these methods
+ .commitEach()
+ .commitAfter(10)
+ .commitAll()
+ .commitNone() // the default
+
+ .loadCSV(inputstream)
+ .fields(ID, null, TITLE)
+ .execute();
+
+
+Loader<TAuthor> loader = /* .. */ .execute();
+
+// The number of processed rows
+int processed = loader.processed();
+
+// The number of stored rows (INSERT or UPDATE)
+int stored = loader.stored();
+
+// The number of ignored rows (due to errors, or duplicate rule)
+int ignored = loader.ignored();
+
+// The errors that may have occurred during loading
+List<LoaderError> errors = loader.errors();
+LoaderError error = errors.get(0);
+
+// The exception that caused the error
+SQLException exception = error.exception();
+
+// The row that caused the error
+int rowIndex = error.rowIndex();
+String[] row = error.row();
+
+// The query that caused the error
+Query query = error.query();
+
+ XML
+
-
The jOOQ User Manual : Advanced topics : Importing data from XML, CSV previous
+The jOOQ User Manual : Advanced topics : Importing data from XML, CSV previous
-
The jOOQ User Manual : Advanced topics : Master data generation previous : next
+The jOOQ User Manual : Advanced topics : Master data generation. Enumeration tables previous : next
Enumeration tables
@@ -127,7 +127,7 @@ public class TBookRecord extends UpdatableRecordImpl<TBookRecord> {
type is generated.
| The jOOQ User Manual : Advanced topics : Master data generation | previous : next | +The jOOQ User Manual : Advanced topics : Master data generation. Enumeration tables | previous : next |
| The jOOQ User Manual : Advanced topics : Adding Oracle hints to queries | previous : next | +The jOOQ User Manual : Advanced topics : Adding Oracle hints to queries | previous : next |
If you are closely coupling your application to an Oracle database, + you might need to be able to pass hints of the form /*+HINT*/ with + your SQL statements to the Oracle database. For example:
++SELECT /*+ALL_ROWS*/ FIRST_NAME, LAST_NAME + FROM T_AUTHOR+ +
This can be done in jOOQ using the .hint() clause in your SELECT statement:
+
+create.select(FIRST_NAME, LAST_NAME)
+ .hint("/*+ALL_ROWS*/")
+ .from(T_AUTHOR);
+
+ Note that you can pass any string in the .hint() clause. If you use + that clause, the passed string will always be put in between the + SELECT [DISTINCT] keywords and the actual projection list
+| The jOOQ User Manual : Advanced topics : Adding Oracle hints to queries | previous : next | +The jOOQ User Manual : Advanced topics : Adding Oracle hints to queries | previous : next |
You may wish to design your database in a way that you have several + instances of your schema. This is useful when you want to cleanly + separate data belonging to several customers / organisation units / + branches / users and put each of those entities' data in a separate + database or schema.
+In our T_AUTHOR example this would mean that you provide a book + reference database to several companies, such as My Book World and + Books R Us. In that case, you'll probably have a schema setup like + this:
+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 + org.jooq.SchemaMapping + class, that you can equip your Factory + with. Take the following example:
+ ++SchemaMapping mapping = new SchemaMapping(); +mapping.add(DEV, "MY_BOOK_WORLD"); + +// Add the mapping to the factory +Factory create = new Factory(connection, SQLDialect.ORACLE, mapping); + +// Run queries with the "mapped" factory +create.selectFrom(T_AUTHOR).fetch();+ +
The query executed with a Factory equipped with the above mapping + will in fact produce this SQL statement:
+SELECT * FROM MY_BOOK_WORLD.T_AUTHOR+
Even if T_AUTHOR was generated from DEV.
+ +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 SchemaMapping + like this:
+ ++SchemaMapping mapping = new SchemaMapping(); +mapping.add(DEV, "MY_BOOK_WORLD"); +mapping.add(LOG, "MY_BOOK_WORLD_LOG");+ +
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
+ + +Another option to switch schema names is to use a default schema for + the Factory's underlying Connection. Many RDBMS support a USE or SET + SCHEMA command, which you can call like this:
+ ++// Set the default schema +Schema MY_BOOK_WORLD = ... +create.use(MY_BOOK_WORLD); + +// Run queries with factory having a default schema +create.selectFrom(T_AUTHOR).fetch();+
Queries generated from the above Factory will produce this kind of SQL statement:
+ ++-- the schema name is omitted from all SQL constructs. +SELECT * FROM T_AUTHOR+ + +
Not only schemata can be mapped, but also tables. If you are not the + owner of the database your application connects to, you might need to + install your schema with some sort of prefix to every table. In our + examples, this might mean that you will have to map DEV.T_AUTHOR to + something MY_BOOK_WORLD.MY_APP__T_AUTHOR, where MY_APP__ is a prefix + applied to all of your tables. This can be achieved by creating the + following mapping:
+ ++SchemaMapping mapping = new SchemaMapping(); +mapping.add(DEV, "MY_BOOK_WORLD"); +mapping.add(T_AUTHOR, "MY_APP__T_AUTHOR"); + +// Add the mapping to the factory +Factory create = new Factory(connection, SQLDialect.ORACLE, mapping); + +// Run queries with the "mapped" factory +create.selectFrom(T_AUTHOR).fetch();+ +
The query executed with a Factory equipped with the above mapping will in fact produce this SQL statement:
++SELECT * FROM MY_BOOK_WORLD.MY_APP__T_AUTHOR+
| The jOOQ User Manual : Advanced topics | previous : next | +The jOOQ User Manual : Advanced topics | previous : next |
This section covers some advanced topics and features that don't fit into any other section.
| The jOOQ User Manual : Advanced topics | previous : next | +The jOOQ User Manual : Advanced topics | previous : next |
+ A + org.jooq.Query + and all its contained objects is a + org.jooq.QueryPart. + QueryParts essentially provide this functionality: +
+Both of these methods are contained in jOOQ's internal API's + org.jooq.QueryPartInternal, which is + internally implemented by every QueryPart. QueryPart internals are best + illustrated with an example.
+ +A simple example can be provided by checking out jOOQ's internal + representation of a + org.jooq.impl.CompareCondition. + It is used for any condition + comparing two fields as for example the T_AUTHOR.ID = T_BOOK.AUTHOR_ID + condition here:
++-- [...] +FROM T_AUTHOR +JOIN T_BOOK ON T_AUTHOR.ID = T_BOOK.AUTHOR_ID +-- [...]+ +
This is how jOOQ implements such a condition:
+ +
+
+@Override
+public final void bind(BindContext context) throws SQLException {
+ // The CompareCondition itself does not bind any variables.
+ // But the two fields involved in the condition might do so...
+ context.bind(field1).bind(field2);
+}
+
+@Override
+public final void toSQL(RenderContext context) {
+ // The CompareCondition delegates rendering of the Fields to the Fields
+ // themselves and connects them using the Condition's comparator operator:
+ context.sql(field1)
+ .sql(" ");
+
+ // If the second field is null, some convenience behaviour can be
+ // implemented here
+ if (field2.isNullLiteral()) {
+ switch (comparator) {
+ case EQUALS:
+ context.sql("is null");
+ break;
+
+ case NOT_EQUALS:
+ context.sql("is not null");
+ break;
+
+ default:
+ throw new IllegalStateException("Cannot compare null with " + comparator);
+ }
+ }
+
+ // By default, also delegate the right hand side's SQL rendering to the
+ // underlying field
+ else {
+ context.sql(comparator.toSQL())
+ .sql(" ")
+ .sql(field2);
+ }
+}
+
+ For more complex examples, please refer to the codebase, directly
+| The jOOQ User Manual : jOOQ classes and their usage : QueryParts and the global architecture | previous : next |
| ID | +AUTHOR_ID | +TITLE | +||||||
|---|---|---|---|---|---|---|---|---|
| 1 | +1 | +1984 | +||||||
| 2 | +1 | +Animal Farm | +
Export your results as text:
+The above query will result in a text document looking like the following one:
+If you are using jOOQ for scripting purposes or in a slim, unlayered + application server, you might be interested in using jOOQ's importing + functionality (see also exporting functionality). You can import data + directly into a table from any of these formats:
+ +The below CSV data represents two author records that may have been + exported previously, by jOOQ's exporting functionality, and then + modified in Microsoft Excel or any other spreadsheet tool:
+ +With jOOQ, you can load this data using various parameters from the + loader API. A simple load may look like this:
+ +Here are various other examples:
+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:
+ +This will be implemented soon...
+